浏览代码

Merge branch 'HeyPuter:main' into main

meetqy 1 年之前
父节点
当前提交
e2cc409635
共有 57 个文件被更改,包括 2558 次插入220 次删除
  1. 0 0
      src/UI/PuterDialog.js
  2. 68 29
      src/UI/UIDesktop.js
  3. 59 33
      src/UI/UIItem.js
  4. 4 4
      src/UI/UIPrompt.js
  5. 4 4
      src/UI/UITaskbar.js
  6. 6 6
      src/UI/UITaskbarItem.js
  7. 22 32
      src/UI/UIWindow.js
  8. 6 6
      src/UI/UIWindowChangePassword.js
  9. 5 5
      src/UI/UIWindowChangeUsername.js
  10. 3 3
      src/UI/UIWindowClaimReferral.js
  11. 2 2
      src/UI/UIWindowColorPicker.js
  12. 5 5
      src/UI/UIWindowConfirmDownload.js
  13. 2 2
      src/UI/UIWindowCopyProgress.js
  14. 14 14
      src/UI/UIWindowDesktopBGSettings.js
  15. 1 1
      src/UI/UIWindowDownloadDirProg.js
  16. 1 1
      src/UI/UIWindowDownloadProgress.js
  17. 2 2
      src/UI/UIWindowEmailConfirmationRequired.js
  18. 4 4
      src/UI/UIWindowFeedback.js
  19. 1 1
      src/UI/UIWindowFontPicker.js
  20. 5 1
      src/UI/UIWindowGetCopyLink.js
  21. 3 3
      src/UI/UIWindowItemProperties.js
  22. 6 6
      src/UI/UIWindowLogin.js
  23. 1 1
      src/UI/UIWindowMoveProgress.js
  24. 7 6
      src/UI/UIWindowMyWebsites.js
  25. 1 1
      src/UI/UIWindowNewFolderProgress.js
  26. 3 3
      src/UI/UIWindowNewPassword.js
  27. 2 2
      src/UI/UIWindowProgressEmptyTrash.js
  28. 3 3
      src/UI/UIWindowPublishWebsite.js
  29. 1 1
      src/UI/UIWindowQR.js
  30. 3 3
      src/UI/UIWindowRecoverPassword.js
  31. 4 4
      src/UI/UIWindowRefer.js
  32. 8 8
      src/UI/UIWindowSaveAccount.js
  33. 3 3
      src/UI/UIWindowSessionList.js
  34. 7 7
      src/UI/UIWindowSignup.js
  35. 3 3
      src/UI/UIWindowUploadProgress.js
  36. 5 0
      src/globals.js
  37. 53 6
      src/helpers.js
  38. 5 5
      src/helpers/new_context_menu_item.js
  39. 52 0
      src/i18n/i18n.js
  40. 8 0
      src/i18n/i18nChangeLanguage.js
  41. 147 0
      src/i18n/translations/bn.js
  42. 148 0
      src/i18n/translations/da.js
  43. 148 0
      src/i18n/translations/de.js
  44. 148 0
      src/i18n/translations/en.js
  45. 148 0
      src/i18n/translations/fa.js
  46. 207 0
      src/i18n/translations/fi.js
  47. 148 0
      src/i18n/translations/fr.js
  48. 148 0
      src/i18n/translations/it.js
  49. 148 0
      src/i18n/translations/ko.js
  50. 148 0
      src/i18n/translations/nb.js
  51. 148 0
      src/i18n/translations/nn.js
  52. 147 0
      src/i18n/translations/ro.js
  53. 148 0
      src/i18n/translations/sv.js
  54. 31 0
      src/i18n/translations/translations.js
  55. 148 0
      src/i18n/translations/zh.js
  56. 5 0
      src/initgui.js
  57. 1 0
      src/static-assets.js

文件差异内容过多而无法显示
+ 0 - 0
src/UI/PuterDialog.js


+ 68 - 29
src/UI/UIDesktop.js

@@ -34,6 +34,7 @@ import UIWindowQR from "./UIWindowQR.js"
 import UIWindowRefer from "./UIWindowRefer.js"
 import UITaskbar from "./UITaskbar.js"
 import new_context_menu_item from "../helpers/new_context_menu_item.js"
+import ChangeLanguage from "../i18n/i18nChangeLanguage.js"
 
 async function UIDesktop(options){
     let h = '';
@@ -622,10 +623,30 @@ async function UIDesktop(options){
                     // Sort by
                     // -------------------------------------------
                     {
-                        html: "Sort by",
+                        html: i18n('sort_by'),
                         items: [
                             {
-                                html: `Name`,
+                                html: i18n('auto_arrange'),
+                                icon: is_auto_arrange_enabled ? '✓' : '',
+                                onClick: async function(){
+                                    is_auto_arrange_enabled = !is_auto_arrange_enabled;
+                                    store_auto_arrange_preference(is_auto_arrange_enabled);
+                                    if(is_auto_arrange_enabled){
+                                        sort_items(el_desktop, $(el_desktop).attr('data-sort_by'), $(el_desktop).attr('data-sort_order'));
+                                        set_sort_by(options.desktop_fsentry.uid, $(el_desktop).attr('data-sort_by'), $(el_desktop).attr('data-sort_order'))
+                                        clear_desktop_item_positions(el_desktop);
+                                    }else{
+                                        set_desktop_item_positions(el_desktop)
+                                    }
+                                }
+                            },
+                            // -------------------------------------------
+                            // -
+                            // -------------------------------------------
+                            '-',
+                            {
+                                html: i18n('name'),
+                                disabled: !is_auto_arrange_enabled,
                                 icon: $(el_desktop).attr('data-sort_by') === 'name' ? '✓' : '',
                                 onClick: async function(){
                                     sort_items(el_desktop, 'name', $(el_desktop).attr('data-sort_order'));
@@ -633,7 +654,8 @@ async function UIDesktop(options){
                                 }
                             },
                             {
-                                html: `Date modified`,
+                                html: i18n('date_modified'),
+                                disabled: !is_auto_arrange_enabled,
                                 icon: $(el_desktop).attr('data-sort_by') === 'modified' ? '✓' : '',
                                 onClick: async function(){
                                     sort_items(el_desktop, 'modified', $(el_desktop).attr('data-sort_order'));
@@ -641,7 +663,8 @@ async function UIDesktop(options){
                                 }
                             },
                             {
-                                html: `Type`,
+                                html: i18n('type'),
+                                disabled: !is_auto_arrange_enabled,
                                 icon: $(el_desktop).attr('data-sort_by') === 'type' ? '✓' : '',
                                 onClick: async function(){
                                     sort_items(el_desktop, 'type', $(el_desktop).attr('data-sort_order'));
@@ -649,7 +672,8 @@ async function UIDesktop(options){
                                 }
                             },
                             {
-                                html: `Size`,
+                                html: i18n('size'),
+                                disabled: !is_auto_arrange_enabled,
                                 icon: $(el_desktop).attr('data-sort_by') === 'size' ? '✓' : '',
                                 onClick: async function(){
                                     sort_items(el_desktop, 'size', $(el_desktop).attr('data-sort_order'));
@@ -661,7 +685,8 @@ async function UIDesktop(options){
                             // -------------------------------------------
                             '-',
                             {
-                                html: `Ascending`,
+                                html: i18n('ascending'),
+                                disabled: !is_auto_arrange_enabled,
                                 icon: $(el_desktop).attr('data-sort_order') === 'asc' ? '✓' : '',
                                 onClick: async function(){
                                     const sort_by = $(el_desktop).attr('data-sort_by')
@@ -670,7 +695,8 @@ async function UIDesktop(options){
                                 }
                             },
                             {
-                                html: `Descending`,
+                                html: i18n('descending'),
+                                disabled: !is_auto_arrange_enabled,
                                 icon: $(el_desktop).attr('data-sort_order') === 'desc' ? '✓' : '',
                                 onClick: async function(){
                                     const sort_by = $(el_desktop).attr('data-sort_by')
@@ -684,7 +710,7 @@ async function UIDesktop(options){
                     // Refresh
                     // -------------------------------------------
                     {
-                        html: "Refresh",
+                        html: i18n('refresh'),
                         onClick: function(){
                             refresh_item_container(el_desktop);
                         }
@@ -693,7 +719,8 @@ async function UIDesktop(options){
                     // Show/Hide hidden files
                     // -------------------------------------------
                     {
-                        html: `${window.user_preferences.show_hidden_files ? 'Hide' : 'Show'} hidden files`,
+                        html: i18n('show_hidden'),
+                        icon: window.user_preferences.show_hidden_files ? '✓' : '',
                         onClick: function(){
                             window.mutate_user_preferences({
                                 show_hidden_files : !window.user_preferences.show_hidden_files,
@@ -717,7 +744,7 @@ async function UIDesktop(options){
                     // Paste
                     // -------------------------------------------
                     {
-                        html: "Paste",
+                        html: i18n('paste'),
                         disabled: clipboard.length > 0 ? false : true,
                         onClick: function(){
                             if(clipboard_op === 'copy')
@@ -730,7 +757,7 @@ async function UIDesktop(options){
                     // Undo
                     // -------------------------------------------
                     {
-                        html: "Undo",
+                        html: i18n('undo'),
                         disabled: actions_history.length > 0 ? false : true,
                         onClick: function(){
                             undo_last_action();
@@ -740,21 +767,12 @@ async function UIDesktop(options){
                     // Upload Here
                     // -------------------------------------------
                     {
-                        html: "Upload Here",
+                        html: i18n('upload_here'),
                         onClick: function(){
                             init_upload_using_dialog(el_desktop);
                         }
                     },
                     // -------------------------------------------
-                    // Request Files
-                    // -------------------------------------------
-                    // {
-                    //     html: "Request Files",
-                    //     onClick: function(){
-                    //         UIWindowRequestFiles({dir_path: desktop_path})                       
-                    //     }
-                    // },
-                    // -------------------------------------------
                     // -
                     // -------------------------------------------
                     '-',
@@ -762,7 +780,7 @@ async function UIDesktop(options){
                     // Change Desktop Background…
                     // -------------------------------------------
                     {
-                        html: "Change Desktop Background…",
+                        html: i18n('change_desktop_background'),
                         onClick: function(){
                             UIWindowDesktopBGSettings();
                         }
@@ -1053,7 +1071,7 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
     if(window.user.is_temp){
         items.push(            
             {
-                html: `Save Session`,
+                html: i18n('save_session'),
                 icon: `<svg style="margin-bottom: -4px; width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48"><g transform="translate(0, 0)"><path d="M45.521,39.04L27.527,5.134c-1.021-1.948-3.427-2.699-5.375-1.679-.717,.376-1.303,.961-1.679,1.679L2.479,39.04c-.676,1.264-.635,2.791,.108,4.017,.716,1.207,2.017,1.946,3.42,1.943H41.993c1.403,.003,2.704-.736,3.42-1.943,.743-1.226,.784-2.753,.108-4.017ZM23.032,15h1.937c.565,0,1.017,.467,1,1.031l-.438,14c-.017,.54-.459,.969-1,.969h-1.062c-.54,0-.983-.429-1-.969l-.438-14c-.018-.564,.435-1.031,1-1.031Zm.968,25c-1.657,0-3-1.343-3-3s1.343-3,3-3,3,1.343,3,3-1.343,3-3,3Z" fill="#ffbb00"></path></g></svg>`,
                 icon_active: `<svg style="margin-bottom: -4px; width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48"><g transform="translate(0, 0)"><path d="M45.521,39.04L27.527,5.134c-1.021-1.948-3.427-2.699-5.375-1.679-.717,.376-1.303,.961-1.679,1.679L2.479,39.04c-.676,1.264-.635,2.791,.108,4.017,.716,1.207,2.017,1.946,3.42,1.943H41.993c1.403,.003,2.704-.736,3.42-1.943,.743-1.226,.784-2.753,.108-4.017ZM23.032,15h1.937c.565,0,1.017,.467,1,1.031l-.438,14c-.017,.54-.459,.969-1,.969h-1.062c-.54,0-.983-.429-1-.969l-.438-14c-.018-.564,.435-1.031,1-1.031Zm.968,25c-1.657,0-3-1.343-3-3s1.343-3,3-3,3,1.343,3,3-1.343,3-3,3Z" fill="#ffbb00"></path></g></svg>`,
                 onClick: async function(){
@@ -1105,7 +1123,7 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
 
         items.push(            
             {
-                html: 'Add existing account',
+                html: i18n('add_existing_account'),
                 // icon: l_user.username === user.username ? '✓' : '',
                 onClick: async function(val){
                     await UIWindowLogin({
@@ -1126,6 +1144,19 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
 
     }
 
+    // -------------------------------------------
+    // Load avaialble languages
+    // -------------------------------------------
+    const supoprtedLanguagesItems = ListSupportedLanugages().map(lang => {
+        return {
+            html: lang.name,
+            icon: window.locale === lang.code ? '✓' : '',
+            onClick: async function(){
+                ChangeLanguage(lang.code);
+            }
+        }
+    });
+
     UIContextMenu({
         id: 'user-options-menu',
         parent_element: parent_element,
@@ -1136,7 +1167,7 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
             // My Websites
             //--------------------------------------------------
             {
-                html: "My Websites",
+                html: i18n('my_websites'),
                 onClick: async function(){
                     UIWindowMyWebsites();
                 }
@@ -1145,7 +1176,7 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
             // Change Username
             //--------------------------------------------------
             {
-                html: "Change Username",
+                html: i18n('change_username'),
                 onClick: async function(){
                     UIWindowChangeUsername();
                 }
@@ -1155,16 +1186,24 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
             // Change Password
             //--------------------------------------------------
             {
-                html: "Change Password",
+                html: i18n('change_password'),
                 onClick: async function(){
                     UIWindowChangePassword();
                 }
             },
+
+            //--------------------------------------------------
+            // Change Language
+            //--------------------------------------------------
+            {
+                html: i18n('change_language'),
+                items: supoprtedLanguagesItems
+            },
             //--------------------------------------------------
             // Contact Us
             //--------------------------------------------------
             {
-                html: "Contact Us",
+                html: i18n('contact_us'),
                 onClick: async function(){
                     UIWindowFeedback();
                 }
@@ -1178,7 +1217,7 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
             // Log Out
             //--------------------------------------------------
             {
-                html: "Log Out",
+                html: i18n('log_out'),
                 onClick: async function(){
                     // see if there are any open windows, if yes notify user
                     if($('.window-app').length > 0){

+ 59 - 33
src/UI/UIItem.js

@@ -187,6 +187,13 @@ function UIItem(options){
         update_explorer_footer_item_count(el_window);
     }
 
+    // position
+    if(!is_auto_arrange_enabled && options.position && $(el_item).closest('.item-container').attr('data-path') === window.desktop_path){
+        el_item.style.position = 'absolute';
+        el_item.style.left = options.position.left + 'px';
+        el_item.style.top = options.position.top + 'px';
+    }
+
     // --------------------------------------------------------
     // Dragster
     // allow dragging of local files on this window, if it's is_dir
@@ -335,6 +342,19 @@ function UIItem(options){
             }
         },
         stop: function(event, ui){
+            // Allow rearranging only if item is on desktop, not trash container, auto arrange is disabled and item is not dropped into another item
+            if($(el_item).closest('.item-container').attr('data-path') === window.desktop_path && 
+                !is_auto_arrange_enabled && $(el_item).attr('data-path') !== trash_path && !ui.helper.data('dropped') &&
+                // Item must be dropped on the Desktop
+                mouseover_window === undefined){
+    
+                el_item.style.position = 'absolute';
+                el_item.style.left = ui.position.left + 'px';
+                el_item.style.top = ui.position.top + 'px';
+                $('.ui-draggable-dragging').remove();
+                desktop_item_positions[$(el_item).attr('data-uid')] = ui.position;
+                save_desktop_item_positions()
+            }
             $('.item-selected-clone').remove();
             $('.draggable-count-badge').remove();
             // re-enable all droppable UIItems that are not a dir
@@ -363,6 +383,9 @@ function UIItem(options){
             if(event.ctrlKey && path.dirname($(ui.draggable).attr('data-path')) === window.trash_path)
                 return;
 
+            // Adding a flag to know whether item is rearraged or dropped
+            ui.helper.data('dropped', true);
+
             const items_to_move = []
             
             // First item
@@ -437,6 +460,10 @@ function UIItem(options){
                 }
                 // Otherwise, move items
                 else if(options.is_dir){
+                    if($(el_item).closest('.item-container').attr('data-path') === window.desktop_path){
+                        delete desktop_item_positions[$(el_item).attr('data-uid')];
+                        save_desktop_item_positions()
+                    }
                     move_items(items_to_move, $(el_item).attr('data-shortcut_to_path') !== '' ? $(el_item).attr('data-shortcut_to_path') : $(el_item).attr('data-path'));
                 }
             }
@@ -736,7 +763,7 @@ function UIItem(options){
             // -------------------------------------------
             if(are_trashed){
                 menu_items.push({
-                    html: "Restore",
+                    html: i18n('restore'),
                     onClick: function(){
                         $selected_items.each(function() {
                             const ell = this;
@@ -755,7 +782,7 @@ function UIItem(options){
                 // Donwload
                 // -------------------------------------------
                 menu_items.push({
-                    html: 'Download',
+                    html: i18n('Download'),
                     onClick: async function(){
                         let items = [];
                         for (let index = 0; index < $selected_items.length; index++) {
@@ -769,7 +796,7 @@ function UIItem(options){
                 // Zip
                 // -------------------------------------------
                 menu_items.push({
-                    html: 'Zip',
+                    html: i18n('zip'),
                     onClick: async function(){
                         let items = [];
                         for (let index = 0; index < $selected_items.length; index++) {
@@ -788,7 +815,7 @@ function UIItem(options){
             // Cut
             // -------------------------------------------
             menu_items.push({
-                html: "Cut",
+                html: i18n('cut'),
                 onClick: function(){
                     window.clipboard_op= 'move';
                     window.clipboard = [];
@@ -804,7 +831,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!are_trashed){
                 menu_items.push({
-                    html: "Copy",
+                    html: i18n('copy'),
                     onClick: function(){
                         window.clipboard_op= 'copy';
                         window.clipboard = [];
@@ -824,7 +851,7 @@ function UIItem(options){
             // -------------------------------------------
             if(are_trashed){
                 menu_items.push({
-                    html: 'Delete Permanently',
+                    html: i18n('delete_permanently'),
                     onClick: async function(){
                         const alert_resp = await UIAlert({
                             message: `Are you sure you want to permanently delete these items?`,
@@ -863,7 +890,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!are_trashed && window.feature_flags.create_shortcut){
                 menu_items.push({
-                    html: 'Create Shortcut',
+                    html: i18n('create_shortcut'),
                     onClick: async function(){
                         $selected_items.each(function() {
                             let base_dir = path.dirname($(this).attr('data-path'));
@@ -889,7 +916,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!are_trashed){
                 menu_items.push({
-                    html: 'Delete',
+                    html: i18n('delete'),
                     onClick: async function(){
                         move_items($selected_items, trash_path);
                     }
@@ -909,7 +936,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trashed){
                 menu_items.push({
-                    html: 'Open',
+                    html: i18n('open'),
                     onClick: function(){
                         open_item({item: el_item});
                     }
@@ -965,7 +992,7 @@ function UIItem(options){
                 }
                 // add all suitable apps
                 menu_items.push({
-                    html: 'Open With',
+                    html: i18n('open_with'),
                     items: items,
                 });
 
@@ -981,7 +1008,7 @@ function UIItem(options){
             // -------------------------------------------
             if($(el_item).closest('.window-body').length > 0 && options.is_dir){
                 menu_items.push({
-                    html: 'Open in New Window',
+                    html: i18n('open_in_new_window'),
                     onClick: function(){
                         if(options.is_dir){
                             open_item({item: el_item, new_window: true})
@@ -1000,7 +1027,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trashed && !is_trash && options.is_dir){
                 menu_items.push({
-                    html: 'Publish As Website',
+                    html: i18n('publish_as_website'),
                     disabled: !options.is_dir,
                     onClick: async function () {
                         if(window.require_email_verification_to_publish_website){
@@ -1027,7 +1054,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trashed && !is_trash && options.is_dir){
                 menu_items.push({
-                    html: 'Deploy As App',
+                    html: i18n('deploy_as_app'),
                     disabled: !options.is_dir,
                     onClick: async function () {
                         launch_app({
@@ -1049,19 +1076,18 @@ function UIItem(options){
             // -------------------------------------------
             if(is_trash){
                 menu_items.push({
-                    html: 'Empty Trash',
+                    html: i18n('empty_trash'),
                     onClick: async function(){
                         empty_trash();
                     }
                 });
-
             }
             // -------------------------------------------
             // Donwload
             // -------------------------------------------
             if(!is_trash && !is_trashed && (options.associated_app_name === null || options.associated_app_name === undefined)){
                 menu_items.push({
-                    html: 'Download',
+                    html: i18n('Download'),
                     disabled: options.is_dir && !window.feature_flags.download_directory,
                     onClick: async function(){
                         if(options.is_dir)
@@ -1078,11 +1104,11 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trashed && !is_trash && (options.associated_app_name === null || options.associated_app_name === undefined)){
                 menu_items.push({
-                    html: 'Get Copy Link',
+                    html: i18n('get_copy_link'),
                     onClick: async function(){
                         if(window.user.is_temp && 
                             !await UIWindowSaveAccount({
-                                message: 'Please create an account to proceed.',
+                                message: i18n('save_account_to_get_copy_link'),
                                 send_confirmation_code: true,
                                 window_options: {
                                     backdrop: true,
@@ -1107,7 +1133,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trash && !is_trashed && !$(el_item).attr('data-path').endsWith('.zip')){
                 menu_items.push({
-                    html: "Zip",
+                    html: i18n('zip'),
                     onClick: function(){
                         zipItems(el_item, path.dirname($(el_item).attr('data-path')), false);
                     }
@@ -1118,7 +1144,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trash && !is_trashed && $(el_item).attr('data-path').endsWith('.zip')){
                 menu_items.push({
-                    html: "Unzip",
+                    html: i18n('unzip'),
                     onClick: async function(){
                         const zip = new JSZip();
                         let filPath = $(el_item).attr('data-path');
@@ -1146,7 +1172,7 @@ function UIItem(options){
             // -------------------------------------------
             if(is_trashed){
                 menu_items.push({
-                    html: 'Restore',
+                    html: i18n('restore'),
                     onClick: async function(){
                         let metadata = $(el_item).attr('data-metadata') === '' ? {} : JSON.parse($(el_item).attr('data-metadata'))
                         move_items([el_item], path.dirname(metadata.original_path));
@@ -1163,7 +1189,7 @@ function UIItem(options){
             // -------------------------------------------
             if($(el_item).attr('data-immutable') === '0'){
                 menu_items.push({
-                    html: "Cut",
+                    html: i18n('cut'),
                     onClick: function(){
                         window.clipboard_op= 'move';
                         window.clipboard= [options.path];
@@ -1175,7 +1201,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trashed && !is_trash){
                 menu_items.push({
-                    html: "Copy",
+                    html: i18n('copy'),
                     onClick: function(){
                         window.clipboard_op= 'copy';
                         window.clipboard= [{path: options.path}];
@@ -1187,7 +1213,7 @@ function UIItem(options){
             // -------------------------------------------
             if($(el_item).attr('data-is_dir') === '1' && !is_trashed && !is_trash){
                 menu_items.push({
-                    html: "Paste Into Folder",
+                    html: i18n('paste_into_folder'),
                     disabled: clipboard.length > 0 ? false : true,
                     onClick: function(){
                         if(clipboard_op === 'copy')
@@ -1208,7 +1234,7 @@ function UIItem(options){
             // -------------------------------------------
             if(!is_trashed && window.feature_flags.create_shortcut){
                 menu_items.push({
-                    html: 'Create Shortcut',
+                    html: i18n('create_shortcut'),
                     onClick: async function(){
                         let base_dir = path.dirname($(el_item).attr('data-path'));
                         // Trash on Desktop is a special case
@@ -1232,7 +1258,7 @@ function UIItem(options){
             // -------------------------------------------
             if($(el_item).attr('data-immutable') === '0' && !is_trashed){
                 menu_items.push({
-                    html: 'Delete',
+                    html: i18n('delete'),
                     onClick: async function(){
                         move_items([el_item], trash_path);
                     }
@@ -1243,7 +1269,7 @@ function UIItem(options){
             // -------------------------------------------
             if(is_trashed){
                 menu_items.push({
-                    html: 'Delete Permanently',
+                    html: i18n('delete_permanently'),
                     onClick: async function(){
                         const alert_resp = await UIAlert({
                             message: `Are you sure you want to permanently delete this item?`,
@@ -1280,7 +1306,7 @@ function UIItem(options){
             // -------------------------------------------
             if($(el_item).attr('data-immutable') === '0' && !is_trashed && !is_trash){
                 menu_items.push({
-                    html: "Rename",
+                    html: i18n('rename'),
                     onClick: function(){
                         activate_item_name_editor(el_item)
                     }
@@ -1294,7 +1320,7 @@ function UIItem(options){
             // Properties
             // -------------------------------------------
             menu_items.push({
-                html: "Properties",
+                html: i18n('properties'),
                 onClick: function(){
                     let window_height = 500;
                     let window_width = 450;
@@ -1387,8 +1413,8 @@ $(document).on('contextmenu', '.item-has-website-url-badge', async function(e){
         items: [
             // Open
             {
-                html: `Open in New Tab <img src="${window.icons['launch.svg']}" style="width:10px; height:10px; margin-left: 5px;">` ,
-                html_active: `Open in New Tab <img src="${window.icons['launch-white.svg']}" style="width:10px; height:10px; margin-left: 5px;">` ,
+                html: `${i18n('open_in_new_tab')} <img src="${window.icons['launch.svg']}" style="width:10px; height:10px; margin-left: 5px;">` ,
+                html_active: `${i18n('open_in_new_tab')} <img src="${window.icons['launch-white.svg']}" style="width:10px; height:10px; margin-left: 5px;">` ,
                 onClick: function(){
                     const website_url = $(e.target).closest('.item').attr('data-website_url');
                     if(website_url){
@@ -1398,7 +1424,7 @@ $(document).on('contextmenu', '.item-has-website-url-badge', async function(e){
             },
             // Copy Link
             {
-                html: 'Copy Link',
+                html: i18n('copy_link'),
                 onClick: async function(){
                     const website_url = $(e.target).closest('.item').attr('data-website_url');
                     if(website_url){
@@ -1499,7 +1525,7 @@ window.activate_item_name_editor= function(el_item){
     }
     // files in trash cannot be renamed, user should be notified with an Alert.
     else if(path.dirname($(el_item).attr('data-path')) === window.trash_path){
-        UIAlert(`This item can't be renamed because it's in the trash. To rename this item, first drag it out of the Trash.`)
+        UIAlert(i18n('items_in_trash_cannot_be_renamed'));
         return;
     }
 

+ 4 - 4
src/UI/UIPrompt.js

@@ -37,8 +37,8 @@ function UIPrompt(options){
         // provide an 'OK' button if no buttons are provided
         if(!options.buttons || options.buttons.length === 0){
             options.buttons = [
-                {label: 'Cancel', value: false, type: 'default'},
-                {label: 'OK', value: true, type: 'primary'},
+                {label: i18n('Cancel'), value: false, type: 'default'},
+                {label: i18n('OK'), value: true, type: 'primary'},
             ]
         }
 
@@ -52,8 +52,8 @@ function UIPrompt(options){
         // buttons
         if(options.buttons && options.buttons.length > 0){
             h += `<div style="overflow:hidden; margin-top:20px; float:right;">`;
-                h += `<button class="button button-default prompt-resp-button prompt-resp-btn-cancel" data-label="Cancel" style="padding: 0 20px;">Cancel</button>`;
-                h += `<button class="button button-primary prompt-resp-button prompt-resp-btn-ok" data-label="OK" data-value="true" autofocus>OK</button>`;
+                h += `<button class="button button-default prompt-resp-button prompt-resp-btn-cancel" data-label="${i18n('Cancel')}" style="padding: 0 20px;">${i18n('Cancel')}</button>`;
+                h += `<button class="button button-primary prompt-resp-button prompt-resp-btn-ok" data-label="${i18n('OK')}" data-value="true" autofocus>${i18n('OK')}</button>`;
             h += `</div>`;
         }
 

+ 4 - 4
src/UI/UITaskbar.js

@@ -50,7 +50,7 @@ async function UITaskbar(options){
     //---------------------------------------------
     UITaskbarItem({
         icon: window.icons['start.svg'],
-        name: 'Start',
+        name: i18n('start'),
         sortable: false,
         keep_in_taskbar: true,
         disable_context_menu: true,
@@ -95,7 +95,7 @@ async function UITaskbar(options){
             // -------------------------------------------
             if(launch_apps.recent.length > 0){
                 // heading
-                apps_str += `<h1 class="start-section-heading start-section-heading-recent">Recent</h1>`;
+                apps_str += `<h1 class="start-section-heading start-section-heading-recent">${i18n('recent')}</h1>`;
 
                 // apps
                 apps_str += `<div class="launch-apps-recent">`;
@@ -116,7 +116,7 @@ async function UITaskbar(options){
             if(launch_apps.recommended.length > 0){
                 // heading
                 apps_str += `<h1 class="start-section-heading start-section-heading-recommended" style="${launch_apps.recent.length > 0 ? 'padding-top: 30px;' : ''}">Recommended</h1>`;
-                
+
                 // apps
                 apps_str += `<div class="launch-apps-recommended">`;
                 for (let index = 0; index < launch_apps.recommended.length; index++) {
@@ -158,7 +158,7 @@ async function UITaskbar(options){
                 }
             });
         }
-    });            
+    });
 
     //---------------------------------------------
     // add `Explorer` to the taskbar

+ 6 - 6
src/UI/UITaskbarItem.js

@@ -137,7 +137,7 @@ function UITaskbarItem(options){
 
             // Empty Trash menu item
             menu_items.push({
-                html: 'Empty Trash',
+                html: i18n('empty_trash'),
                 val: $(this).attr('data-id'),
                 onClick: async function(){
                     empty_trash();
@@ -150,7 +150,7 @@ function UITaskbarItem(options){
         //------------------------------------------
         if(options.keep_in_taskbar && !options.lock_keep_in_taskbar){
             menu_items.push({
-                html: 'Remove from Taskbar',
+                html: i18n('remove_from_taskbar'),
                 val: $(this).attr('data-id'),
                 onClick: function(){
                     $(el_taskbar_item).attr('data-keep-in-taskbar', 'false');
@@ -167,7 +167,7 @@ function UITaskbarItem(options){
         //------------------------------------------
         else if(!options.keep_in_taskbar){
             menu_items.push({
-                html: 'Keep in Taskbar',
+                html: i18n('keep_in_taskbar'),
                 val: $(this).attr('data-id'),
                 onClick: function(){
                     $(el_taskbar_item).attr('data-keep-in-taskbar', 'true');
@@ -186,7 +186,7 @@ function UITaskbarItem(options){
             // Show All Windows
             // -------------------------------------------
             menu_items.push({
-                html: "Show All Windows",
+                html: i18n('show_all_windows'),
                 onClick: function(){
                     if(open_windows > 0)
                         $(el_taskbar_item).trigger('click');
@@ -196,7 +196,7 @@ function UITaskbarItem(options){
             // Hide All Windows
             // -------------------------------------------
             menu_items.push({
-                html: "Hide All Windows",
+                html: i18n('hide_all_windows'),
                 onClick: function(){
                     if(open_windows > 0)
                         $(`.window[data-app="${options.app}"]`).hideWindow();
@@ -206,7 +206,7 @@ function UITaskbarItem(options){
             // Close All Windows
             // -------------------------------------------
             menu_items.push({
-                html: "Close All Windows",
+                html: i18n('close_all_windows'),
                 onClick: function(){
                     $(`.window[data-app="${options.app}"]`).close();
                 }

+ 22 - 32
src/UI/UIWindow.js

@@ -295,7 +295,7 @@ async function UIWindow(options) {
                         frameborder="0" webkitallowfullscreen="webkitallowfullscreen" mozallowfullscreen="mozallowfullscreen"
                         ${options.iframe_url ? 'src="'+ html_encode(options.iframe_url)+'"' : ''}
                         ${options.iframe_srcdoc ? 'srcdoc="'+ html_encode(options.iframe_srcdoc) +'"' : ''}
-                        allow = "accelerometer; camera; encrypted-media; display-capture; geolocation; gyroscope; microphone; midi; clipboard-read; clipboard-write; web-share; fullscreen;"
+                        allow = "accelerometer; camera; encrypted-media; gamepad; display-capture; geolocation; gyroscope; microphone; midi; clipboard-read; clipboard-write; web-share; fullscreen;"
                         sandbox="allow-forms allow-modals allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-downloads allow-presentation"></iframe>`;
             }
             // custom body
@@ -1812,10 +1812,10 @@ async function UIWindow(options) {
                         // Sort by
                         // -------------------------------------------
                         {
-                            html: "Sort by",
+                            html: i18n('sort_by'),
                             items: [
                                 {
-                                    html: `Name`,
+                                    html: i18n('name'),
                                     icon: $(el_window).attr('data-sort_by') === 'name' ? '✓' : '',
                                     onClick: async function(){
                                         sort_items(el_window_body, 'name', $(el_window).attr('data-sort_order'));
@@ -1823,7 +1823,7 @@ async function UIWindow(options) {
                                     }
                                 },
                                 {
-                                    html: `Date modified`,
+                                    html: i18n('date_modified'),
                                     icon: $(el_window).attr('data-sort_by') === 'modified' ? '✓' : '',
                                     onClick: async function(){
                                         sort_items(el_window_body, 'modified', $(el_window).attr('data-sort_order'));
@@ -1831,7 +1831,7 @@ async function UIWindow(options) {
                                     }
                                 },
                                 {
-                                    html: `Type`,
+                                    html: i18n('type'),
                                     icon: $(el_window).attr('data-sort_by') === 'type' ? '✓' : '',
                                     onClick: async function(){
                                         sort_items(el_window_body, 'type', $(el_window).attr('data-sort_order'));
@@ -1839,7 +1839,7 @@ async function UIWindow(options) {
                                     }
                                 },
                                 {
-                                    html: `Size`,
+                                    html: i18n('size'),
                                     icon: $(el_window).attr('data-sort_by') === 'size' ? '✓' : '',
                                     onClick: async function(){
                                         sort_items(el_window_body, 'size', $(el_window).attr('data-sort_order'));
@@ -1851,7 +1851,7 @@ async function UIWindow(options) {
                                 // -------------------------------------------
                                 '-',
                                 {
-                                    html: `Ascending`,
+                                    html: i18n('ascending'),
                                     icon: $(el_window).attr('data-sort_order') === 'asc' ? '✓' : '',
                                     onClick: async function(){
                                         const sort_by = $(el_window).attr('data-sort_by')
@@ -1860,7 +1860,7 @@ async function UIWindow(options) {
                                     }
                                 },
                                 {
-                                    html: `Descending`,
+                                    html: i18n('descending'),
                                     icon: $(el_window).attr('data-sort_order') === 'desc' ? '✓' : '',
                                     onClick: async function(){
                                         const sort_by = $(el_window).attr('data-sort_by')
@@ -1875,7 +1875,7 @@ async function UIWindow(options) {
                         // Refresh
                         // -------------------------------------------
                         {
-                            html: "Refresh",
+                            html: i18n('refresh'),
                             onClick: function(){
                                 refresh_item_container(el_window_body, options);
                             }
@@ -1884,7 +1884,8 @@ async function UIWindow(options) {
                         // Show/Hide hidden files
                         // -------------------------------------------
                         {
-                            html: `${window.user_preferences.show_hidden_files ? "Hide" : "Show"} hidden files`,
+                            html: i18n('show_hidden'),
+                            icon: window.user_preferences.show_hidden_files ? '✓' : '',
                             onClick: function(){
                                 window.mutate_user_preferences({
                                     show_hidden_files : !window.user_preferences.show_hidden_files,
@@ -1908,7 +1909,7 @@ async function UIWindow(options) {
                         // Paste
                         // -------------------------------------------
                         {
-                            html: "Paste",
+                            html: i18n('paste'),
                             disabled: (clipboard.length === 0 || $(el_window).attr('data-path') === '/') ? true : false,
                             onClick: function(){
                                 if(clipboard_op === 'copy')
@@ -1921,7 +1922,7 @@ async function UIWindow(options) {
                         // Undo
                         // -------------------------------------------
                         {
-                            html: "Undo",
+                            html: i18n('undo'),
                             disabled: actions_history.length > 0 ? false : true,
                             onClick: function(){
                                 undo_last_action();
@@ -1931,22 +1932,13 @@ async function UIWindow(options) {
                         // Upload Here
                         // -------------------------------------------
                         {
-                            html: "Upload Here",
+                            html: i18n('upload_here'),
                             disabled: $(el_window).attr('data-path') === '/' ? true : false,
                             onClick: function(){
                                 init_upload_using_dialog(el_window_body, $(el_window).attr('data-path') + '/');
                             }
                         },
                         // -------------------------------------------
-                        // Request Files
-                        // -------------------------------------------
-                        // {
-                        //     html: "Request Files",
-                        //     onClick: function(){
-                        //         UIWindowRequestFiles({dir_path: $(el_window).attr('data-path')})
-                        //     }
-                        // },
-                        // -------------------------------------------
                         // -
                         // -------------------------------------------
                         '-',
@@ -1954,14 +1946,14 @@ async function UIWindow(options) {
                         // Publish As Website
                         // -------------------------------------------
                         {
-                            html: 'Publish As Website',
+                            html: i18n('publish_as_website'),
                             disabled: !options.is_dir,
                             onClick: async function () {
                                 if (window.require_email_verification_to_publish_website) {
                                     if (window.user.is_temp &&
                                         !await UIWindowSaveAccount({
                                             send_confirmation_code: true,
-                                            message: 'Please create an account to proceed.',
+                                            message: i18n('save_account_to_publish_website'),
                                             window_options: {
                                                 backdrop: true,
                                                 close_on_backdrop_click: false,
@@ -1978,7 +1970,7 @@ async function UIWindow(options) {
                         // Deploy as App
                         // -------------------------------------------
                         {
-                            html: 'Deploy as App',
+                            html: i18n('deploy_as_app'),
                             disabled: !options.is_dir,
                             onClick: async function () {
                                 launch_app({
@@ -1989,7 +1981,6 @@ async function UIWindow(options) {
                                         source_path: $(el_window).attr('data-path'),
                                     }
                                 })
-        
                             }
                         },
                         // -------------------------------------------
@@ -2000,19 +1991,18 @@ async function UIWindow(options) {
                         // Properties
                         // -------------------------------------------
                         {
-                            html: "Properties",
+                            html: i18n('properties'),
                             onClick: function(){
                                 let window_height = 500;
                                 let window_width = 450;
-            
+
                                 let left = mouseX;
                                 left -= 200;
                                 left = left > (window.innerWidth - window_width)? (window.innerWidth - window_width) : left;
-            
+
                                 let top = mouseY;
                                 top = top > (window.innerHeight - (window_height + window.taskbar_height + window.toolbar_height))? (window.innerHeight - (window_height + window.taskbar_height + window.toolbar_height)) : top;
-            
-            
+
                                 UIWindowItemProperties(options.title, options.path, options.uid, left, top, window_width, window_height);
                             }
                         },
@@ -2032,7 +2022,7 @@ async function UIWindow(options) {
                             disabled: false,
                             onClick: async function(){
                                 const alert_resp = await UIAlert({
-                                    message: `Are you sure you want to permanently delete the items in Trash?`,
+                                    message: i18n('empty_trash_confirmation'),
                                     buttons:[
                                         {
                                             label: 'Yes',

+ 6 - 6
src/UI/UIWindowChangePassword.js

@@ -29,22 +29,22 @@ async function UIWindowChangePassword(){
         h += `<div class="form-success-msg"></div>`;
         // current password
         h += `<div style="overflow: hidden; margin-bottom: 20px;">`;
-            h += `<label for="current-password-${internal_id}">Current Password</label>`;
+            h += `<label for="current-password-${internal_id}">${i18n('current_password')}</label>`;
             h += `<input id="current-password-${internal_id}" class="current-password" type="password" name="current-password" autocomplete="current-password" />`;
         h += `</div>`;
         // new password
         h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px;">`;
-            h += `<label for="new-password-${internal_id}">New Password</label>`;
+            h += `<label for="new-password-${internal_id}">${i18n('new_password')}</label>`;
             h += `<input id="new-password-${internal_id}" type="password" class="new-password" name="new-password" autocomplete="off" />`;
         h += `</div>`;
         // confirm new password
         h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px;">`;
-            h += `<label for="confirm-new-password-${internal_id}">Confirm New Password</label>`;
+            h += `<label for="confirm-new-password-${internal_id}">${i18n('confirm_new_password')}</label>`;
             h += `<input id="confirm-new-password-${internal_id}" type="password" name="confirm-new-password" class="confirm-new-password" autocomplete="off" />`;
         h += `</div>`;
 
         // Change Password
-        h += `<button class="change-password-btn button button-primary button-block button-normal">Change Password</button>`;
+        h += `<button class="change-password-btn button button-primary button-block button-normal">${i18n('change_password')}</button>`;
     h += `</div>`;
 
     const el_window = await UIWindow({
@@ -93,7 +93,7 @@ async function UIWindowChangePassword(){
             return;
         }
         else if(new_password !== confirm_new_password){
-            $(el_window).find('.form-error-msg').html('`New Password` and `Confirm New Password` do not match.');
+            $(el_window).find('.form-error-msg').html(i18n('passwords_do_not_match'));
             $(el_window).find('.form-error-msg').fadeIn();
             return;
         }
@@ -113,7 +113,7 @@ async function UIWindowChangePassword(){
                 new_pass: new_password,
             }),				
             success: function (data){
-                $(el_window).find('.form-success-msg').html('Password changed successfully.');
+                $(el_window).find('.form-success-msg').html(i18n('password_changed'));
                 $(el_window).find('.form-success-msg').fadeIn();
                 $(el_window).find('input').val('');
             },

+ 5 - 5
src/UI/UIWindowChangeUsername.js

@@ -30,16 +30,16 @@ async function UIWindowChangeUsername(){
         h += `<div class="form-success-msg"></div>`;
         // new username
         h += `<div style="overflow: hidden; margin-top: 10px; margin-bottom: 30px;">`;
-            h += `<label for="confirm-new-username-${internal_id}">New Username</label>`;
+            h += `<label for="confirm-new-username-${internal_id}">${i18n('new_username')}</label>`;
             h += `<input id="confirm-new-username-${internal_id}" type="text" name="new-username" class="new-username" autocomplete="off" />`;
         h += `</div>`;
 
         // Change Username
-        h += `<button class="change-username-btn button button-primary button-block button-normal">Change Username</button>`;
+        h += `<button class="change-username-btn button button-primary button-block button-normal">${i18n('change_username')}</button>`;
     h += `</div>`;
 
     const el_window = await UIWindow({
-        title: 'Change Username',
+        title: i18n('change_username'),
         app: 'change-username',
         single_instance: true,
         icon: null,
@@ -78,7 +78,7 @@ async function UIWindowChangeUsername(){
         const new_username = $(el_window).find('.new-username').val();
 
         if(!new_username){
-            $(el_window).find('.form-error-msg').html('All fields are required.');
+            $(el_window).find('.form-error-msg').html(i18n('all_fields_required'));
             $(el_window).find('.form-error-msg').fadeIn();
             return;
         }
@@ -102,7 +102,7 @@ async function UIWindowChangeUsername(){
                 new_username: new_username, 
             }),				
             success: function (data){
-                $(el_window).find('.form-success-msg').html('Username updated successfully.');
+                $(el_window).find('.form-success-msg').html(i18n('username_changed'));
                 $(el_window).find('.form-success-msg').fadeIn();
                 $(el_window).find('input').val('');
                 // update auth data

+ 3 - 3
src/UI/UIWindowClaimReferral.js

@@ -26,9 +26,9 @@ async function UIWindowClaimReferral(options){
     h += `<div>`;
         h += `<div class="qr-code-window-close-btn generic-close-window-button disable-user-select"> &times; </div>`;
         h += `<img src="${window.icons['present.svg']}" style="width: 70px; margin: 20px auto 20px; display: block; margin-bottom: 20px;">`;
-        h += `<h1 style="font-weight: 400; padding: 0 10px; font-size: 21px; text-align: center; margin-bottom: 0; color: #60626d; -webkit-font-smoothing: antialiased;">You have been referred to Puter by a friend!</h1>`;
-        h += `<p style="text-align: center; font-size: 16px; padding: 20px; font-weight: 400; margin: -10px 10px 0px 10px; -webkit-font-smoothing: antialiased; color: #5f626d;">Create an account and confirm your email address to receive 1 GB of free storage. Your friend will get 1 GB of free storage too.</p>`;
-        h += `<button class="button button-primary button-block create-account-ref-btn" style="display: block;">Create Account</button>`;
+        h += `<h1 style="font-weight: 400; padding: 0 10px; font-size: 21px; text-align: center; margin-bottom: 0; color: #60626d; -webkit-font-smoothing: antialiased;">${i18n('you_have_been_referred_to_puter_by_a_friend')}</h1>`;
+        h += `<p style="text-align: center; font-size: 16px; padding: 20px; font-weight: 400; margin: -10px 10px 0px 10px; -webkit-font-smoothing: antialiased; color: #5f626d;">${i18n('confirm_account_for_free_referral_storage_c2a')}</p>`;
+        h += `<button class="button button-primary button-block create-account-ref-btn" style="display: block;">${i18n('create_account')}</button>`;
     h += `</div>`;
 
     const el_window = await UIWindow({

+ 2 - 2
src/UI/UIWindowColorPicker.js

@@ -42,13 +42,13 @@ async function UIWindowColorPicker(options){
                     h += `</div>`;
 
                     // Select button
-                    h += `<button class="select-btn button button-primary button-block button-normal">Select</button>`
+                    h += `<button class="select-btn button button-primary button-block button-normal">${i18n('select')}</button>`
                 h += `</form>`;
             h += `</div>`;
         h += `</div>`;
         
         const el_window = await UIWindow({
-            title: 'Select color…',
+            title: i18n('select_color'),
             app: 'color-picker',
             single_instance: true,
             icon: null,

+ 5 - 5
src/UI/UIWindowConfirmDownload.js

@@ -34,17 +34,17 @@ async function UIWindowConfirmDownload(options){
                 // Item information
                 h += `<div  style="overflow:hidden;">`;
                     // Name
-                    h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">Name:</span> ${options.name ?? options.url}</p>`;
+                    h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">${i18n('name')}:</span> ${options.name ?? options.url}</p>`;
                     // Type
-                    h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">Type:</span> ${options.is_dir === '1' || options.is_dir === 'true' ? 'Folder' : options.type  ?? 'Unknown File Type'}</p>`;
+                    h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">${i18n('type')}:</span> ${options.is_dir === '1' || options.is_dir === 'true' ? 'Folder' : options.type  ?? 'Unknown File Type'}</p>`;
                     // Source
-                    h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">From:</span> ${options.source}</p>`;
+                    h += `<p style="text-overflow: ellipsis; overflow: hidden;"><span class="dl-conf-item-attr">${i18n('from')}:</span> ${options.source}</p>`;
                 h += `</div>`;
             h += `</div>`;
             // Download
-            h += `<button style="float:right; margin-top: 15px; margin-right: -2px; margin-left:10px;" class="button button-small button-primary btn-download-confirm">Download</button>`;
+            h += `<button style="float:right; margin-top: 15px; margin-right: -2px; margin-left:10px;" class="button button-small button-primary btn-download-confirm">${i18n('download')}</button>`;
             // Cancel
-            h += `<button style="float:right; margin-top: 15px;" class="button button-small btn-download-cancel">Cancel</button>`;
+            h += `<button style="float:right; margin-top: 15px;" class="button button-small btn-download-cancel">${i18n('cancel')}</button>`;
         h +=`</div>`;
 
         const el_window = await UIWindow({

+ 2 - 2
src/UI/UIWindowCopyProgress.js

@@ -29,7 +29,7 @@ async function UIWindowCopyProgress(options){
             // Progress report
             h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
                 // msg
-                h += `<span class="copy-progress-msg">Copying </span>`;
+                h += `<span class="copy-progress-msg">${i18n('copying')} </span>`;
                 h += `<span class="copy-from" style="font-weight:strong;"></span>`;
             h += `</div>`;
             // progress
@@ -42,7 +42,7 @@ async function UIWindowCopyProgress(options){
     h += `</div>`;
 
     const el_window = await UIWindow({
-        title: `Copying`,
+        title: i18n('copying'),
         icon: window.icons[`app-icon-copying.svg`],
         uid: null,
         is_dir: false,

+ 14 - 14
src/UI/UIWindowDesktopBGSettings.js

@@ -30,28 +30,28 @@ async function UIWindowDesktopBGSettings(){
         h += `<div style="padding: 10px; border-bottom: 1px solid #ced7e1;">`;
 
             // type
-            h += `<label>Background:</label>`;
+            h += `<label>${i18n('background')}:</label>`;
             h += `<select class="desktop-bg-type" style="width: 150px; margin-bottom: 20px;">`
-                h += `<option value="picture">Picture</option>`;
-                h += `<option value="color">Color</option>`;
+                h += `<option value="picture">${i18n('picture')}</option>`;
+                h += `<option value="color">${i18n('color')}</option>`;
             h += `</select>`;
 
             // Picture
             h += `<div class="desktop-bg-settings-wrapper desktop-bg-settings-picture">`;
-                h += `<label>Image:</label>`;
-                h += `<button class="button button-default button-small browse">Browse</button>`;
-                h += `<label style="margin-top: 20px;">Fit:</label>`;
+                h += `<label>${i18n('image')}:</label>`;
+                h += `<button class="button button-default button-small browse">${i18n('browse')}</button>`;
+                h += `<label style="margin-top: 20px;">${i18n('fit')}:</label>`;
                 h += `<select class="desktop-bg-fit" style="width: 150px;">`
-                    h += `<option value="cover">Cover</option>`;
-                    h += `<option value="center">Center</option>`;
-                    h += `<option value="contain">Contain</option>`;
-                    h += `<option value="repeat">Repeat</option>`;
+                    h += `<option value="cover">${i18n('cover')}</option>`;
+                    h += `<option value="center">${i18n('center')}</option>`;
+                    h += `<option value="contain">${i18n('contain')}</option>`;
+                    h += `<option value="repeat">${i18n('repeat')}</option>`;
                 h += `</select>`;
             h += `</div>`
 
             // Color
             h += `<div class="desktop-bg-settings-wrapper desktop-bg-settings-color">`;
-                h += `<label>Color:</label>`;
+                h += `<label>${i18n('color')}:</label>`;
                 h += `<div class="desktop-bg-color-blocks">`;
                     h += `<div class="desktop-bg-color-block" data-color="#4F7BB5" style="background-color: #4F7BB5"></div>`;
                     h += `<div class="desktop-bg-color-block" data-color="#545554" style="background-color: #545554"></div>`;
@@ -69,14 +69,14 @@ async function UIWindowDesktopBGSettings(){
             h += `</div>`;
 
             h += `<div style="padding-top: 5px; overflow:hidden; margin-top: 25px; border-top: 1px solid #CCC;">`
-                h += `<button class="button button-primary apply" style="float:right;">Apply</button>`;
-                h += `<button class="button button-default cancel" style="float:right; margin-right: 10px;">Cancel</button>`;
+                h += `<button class="button button-primary apply" style="float:right;">${i18n('apply')}</button>`;
+                h += `<button class="button button-default cancel" style="float:right; margin-right: 10px;">${i18n('cancel')}</button>`;
             h += `</div>`;
 
         h += `</div>`;
 
         const el_window = await UIWindow({
-            title: 'Change Desktop Background…',
+            title: i18n('change_desktop_background'),
             icon: null,
             uid: null,
             is_dir: false,

+ 1 - 1
src/UI/UIWindowDownloadDirProg.js

@@ -25,7 +25,7 @@ async function UIWindowDownloadDirProg(options){
     let h = '';
     // Loading spinner
     h +=`<svg style="height: 40px; width: 40px; padding: 10px; display: block; float: left;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
-    h += `<p style="text-align:left; padding-left:20px; padding-right:20px; overflow:hidden; width: 310px; text-overflow: ellipsis; white-space: nowrap; float:left; font-size:14px;" class="dir-dl-status">${options.defaultText ?? 'Preparing...'}</p>`;
+    h += `<p style="text-align:left; padding-left:20px; padding-right:20px; overflow:hidden; width: 310px; text-overflow: ellipsis; white-space: nowrap; float:left; font-size:14px;" class="dir-dl-status">${options.defaultText ?? i18n('preparing')}</p>`;
 
     const el_window = await UIWindow({
         title: 'Instant Login!',

+ 1 - 1
src/UI/UIWindowDownloadProgress.js

@@ -29,7 +29,7 @@ async function UIWindowDownloadProgress(options){
             // Progress report
             h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
                 // msg
-                h += `<span class="upload-progress-msg">Downloading <strong>${options.item_name ?? ''}</strong></span>`;
+                h += `<span class="upload-progress-msg">${i18n('downloading')} <strong>${options.item_name ?? ''}</strong></span>`;
             h += `</div>`;
             // Progress
             h += `<div class="download-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;

+ 2 - 2
src/UI/UIWindowEmailConfirmationRequired.js

@@ -47,10 +47,10 @@ function UIWindowEmailConfirmationRequired(options){
                 h += `<button type="submit" class="button button-block button-primary email-confirm-btn" style="margin-top:10px;" disabled>${submit_btn_txt}</button>`;
             h += `</form>`;
             h += `<div style="text-align:center; padding:10px; font-size:14px; margin-top:10px;">`;
-                h += `<span class="send-conf-email">Re-send Confirmation Code</span>`;
+                h += `<span class="send-conf-email">${i18n('resend_confirmation_code')}</span>`;
                 if(options.logout_in_footer){
                     h += ` &bull; `;
-                    h += `<span class="conf-email-log-out">Log Out</span>`;
+                    h += `<span class="conf-email-log-out">${i18n('log_out')}</span>`;
                 }
             h += `</div>`;
         h += `</div>`;

+ 4 - 4
src/UI/UIWindowFeedback.js

@@ -28,18 +28,18 @@ async function UIWindowQR(options){
             // success
             h += `<div class="feedback-sent-success">`;
                 h += `<img src="${html_encode(window.icons['c-check.svg'])}" style="width:50px; height:50px; display: block; margin:10px auto;">`;
-                h += `<p style="text-align:center; margin-bottom:10px; color: #005300; padding: 10px;">Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.</p>`;
+                h += `<p style="text-align:center; margin-bottom:10px; color: #005300; padding: 10px;">${i18n('feedback_sent_confirmation')}</p>`;
             h+= `</div>`;
             // form
             h += `<div class="feedback-form">`;
-                h += `<p style="margin-top:0; font-size: 15px; -webkit-font-smoothing: antialiased;">Please use the form below to send us your feedback, comments, and bug reports.</p>`;
+                h += `<p style="margin-top:0; font-size: 15px; -webkit-font-smoothing: antialiased;">${i18n('feedback_c2a')}</p>`;
                 h += `<textarea class="feedback-message" style="width:100%; height: 200px; padding: 10px; box-sizing: border-box;"></textarea>`;
-                h += `<button class="button button-primary send-feedback-btn" style="float: right; margin-bottom: 15px; margin-top: 10px;">Send</button>`;
+                h += `<button class="button button-primary send-feedback-btn" style="float: right; margin-bottom: 15px; margin-top: 10px;">${i18n('send')}</button>`;
             h += `</div>`;
         h += `</div>`;
 
         const el_window = await UIWindow({
-            title: 'Contact Us',
+            title: i18n('contact_us'),
             app: 'feedback',
             single_instance: true,
             icon: null,

+ 1 - 1
src/UI/UIWindowFontPicker.js

@@ -60,7 +60,7 @@ async function UIWindowFontPicker(options){
                     h += `</div>`;
 
                     // Select
-                    h += `<button class="select-btn button button-primary button-block button-normal">Select</button>`
+                    h += `<button class="select-btn button button-primary button-block button-normal">${i18n('Select')}</button>`
                 h += `</form>`;
             h += `</div>`;
         h += `</div>`;

+ 5 - 1
src/UI/UIWindowGetCopyLink.js

@@ -69,7 +69,11 @@ async function UIWindowGetCopyLink(options){
     $(el_window).find('.window-body .downloadable-link').val(url);
 
     $(el_window).find('.window-body .share-copy-link-on-social').on('click', function(e){    
-        const social_links = socialLink({url: url, title: `Get a copy of '${options.name}' on Puter.com!`, description: `Get a copy of '${options.name}' on Puter.com!`});
+        const social_links = socialLink({
+            url: url, 
+            title: i18n('get_a_copy_of_on_puter', options.name, false), 
+            description: i18n('get_a_copy_of_on_puter', options.name, false),
+        });
 
         let social_links_html = ``;
         social_links_html += `<div style="padding: 10px;">`;

+ 3 - 3
src/UI/UIWindowItemProperties.js

@@ -25,8 +25,8 @@ async function UIWindowItemProperties(item_name, item_path, item_uid, left, top,
     h += `<div class="item-props-tabview" style="display: flex; flex-direction: column; height: 100%;">`;
         // tabs
         h += `<div class="item-props-tab">`;
-            h += `<div class="item-props-tab-btn antialiased disable-user-select item-props-tab-selected" data-tab="general">General</div>`;
-            h += `<div class="item-props-tab-btn antialiased disable-user-select item-props-tab-btn-versions" data-tab="versions">Versions</div>`;
+            h += `<div class="item-props-tab-btn antialiased disable-user-select item-props-tab-selected" data-tab="general">${i18n('general')}</div>`;
+            h += `<div class="item-props-tab-btn antialiased disable-user-select item-props-tab-btn-versions" data-tab="versions">${i18n('versions')}</div>`;
         h += `</div>`;
 
         h+= `<div class="item-props-tab-content item-props-tab-content-selected" data-tab="general" style="border-top-left-radius:0;">`;
@@ -44,7 +44,7 @@ async function UIWindowItemProperties(item_name, item_path, item_uid, left, top,
                 h += `<tr><td class="item-prop-label">Versions</td><td class="item-prop-val item-prop-val-versions"></td></tr>`;
                 h += `<tr><td class="item-prop-label">Associated Websites</td><td class="item-prop-val item-prop-val-websites">`;
                 h += `</td></tr>`;
-                h += `<tr><td class="item-prop-label">Access Granted To</td><td class="item-prop-val item-prop-val-permissions"></td></tr>`;
+                h += `<tr><td class="item-prop-label">${i18n('access_granted_to')}</td><td class="item-prop-val item-prop-val-permissions"></td></tr>`;
             h += `</table>`;
         h += `</div>`;
 

+ 6 - 6
src/UI/UIWindowLogin.js

@@ -36,19 +36,19 @@ async function UIWindowLogin(options){
                 h += `<div class="generic-close-window-button"> &times; </div>`;
             h += `<div style="padding: 20px; border-bottom: 1px solid #ced7e1; width: 100%; box-sizing: border-box;">`;
                 // title
-                h += `<h1 class="login-form-title">Log In</h1>`;
+                h += `<h1 class="login-form-title">${i18n('log_in')}</h1>`;
                 // login form
                 h += `<form class="login-form">`;
                     // error msg
                     h += `<div class="login-error-msg"></div>`;
                     // username/email
                     h += `<div style="overflow: hidden;">`;
-                        h += `<label for="email_or_username-${internal_id}">Email or Username</label>`;
+                        h += `<label for="email_or_username-${internal_id}">${i18n('email_or_username')}</label>`;
                         h += `<input id="email_or_username-${internal_id}" class="email_or_username" type="text" name="email_or_username" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false" autocomplete="username"/>`;
                     h += `</div>`;
                     // password with conditional type based based on options.show_password
                     h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px; position: relative;">`;
-                    h += `<label for="password-${internal_id}">Password</label>`;
+                    h += `<label for="password-${internal_id}">${i18n('password')}</label>`;
                     h += `<input id="password-${internal_id}" class="password" type="${options.show_password ? "text" : "password"}" name="password" autocomplete="current-password"/>`;
                     // show/hide icon
                     h += `<span style="position: absolute; right: 5%; top: 50%; cursor: pointer;" id="toggle-show-password-${internal_id}">
@@ -56,15 +56,15 @@ async function UIWindowLogin(options){
                             </span>`;
                     h += `</div>`;
                     // login
-                    h += `<button class="login-btn button button-primary button-block button-normal">Log in</button>`;
+                    h += `<button class="login-btn button button-primary button-block button-normal">${i18n('log_in')}</button>`;
                     // password recovery
-                    h += `<p style="text-align:center; margin-bottom: 0;"><span class="forgot-password-link">Forgot password?</span></p>`;
+                    h += `<p style="text-align:center; margin-bottom: 0;"><span class="forgot-password-link">${i18n('forgot_pass_c2a')}</span></p>`;
                 h += `</form>`;
             h += `</div>`;
             // create account link
             if(options.show_signup_button === undefined || options.show_signup_button){
                 h += `<div class="c2a-wrapper" style="padding:20px;">`;
-                    h += `<button class="signup-c2a-clickable">Create Free Account</button>`;
+                    h += `<button class="signup-c2a-clickable">${i18n('create_free_account')}</button>`;
                 h += `</div>`;
             }
         h += `</div>`;

+ 1 - 1
src/UI/UIWindowMoveProgress.js

@@ -29,7 +29,7 @@ async function UIWindowMoveProgress(options){
             // Progress report
             h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
                 // msg
-                h += `<span class="move-progress-msg">Moving </span>`;
+                h += `<span class="move-progress-msg">${i18n('moving')} </span>`;
                 h += `<span class="move-from" style="font-weight:strong;"></span>`;
             h += `</div>`;
             // progress

+ 7 - 6
src/UI/UIWindowMyWebsites.js

@@ -90,10 +90,10 @@ async function UIWindowMyWebsites(options){
                             h += `</p>`;
                             h += `<p style="margin-bottom:0; margin-top: 20px; font-size: 13px;">`;
                                 h += `<span class="mywebsites-dis-dir" data-dir-uuid="${sites[i].root_dir.id}" data-site-uuid="${sites[i].uid}">`;
-                                h += `<img style="width: 16px; margin-bottom: -2px; margin-right: 4px;" src="${html_encode(window.icons['plug.svg'])}">Disassociate Folder</span>`;
+                                h += `<img style="width: 16px; margin-bottom: -2px; margin-right: 4px;" src="${html_encode(window.icons['plug.svg'])}">${i18n('disassociate_dir')}</span>`;
                             h += `</p>`;
                         }
-                        h += `<p class="mywebsites-no-dir-notice" data-site-uuid="${sites[i].uid}" style="${sites[i].root_dir ? `display:none;` : `display:block;`}">No directory associated with this address.</p>`;
+                        h += `<p class="mywebsites-no-dir-notice" data-site-uuid="${sites[i].uid}" style="${sites[i].root_dir ? `display:none;` : `display:block;`}">${i18n('no_dir_associated_with_site')}</p>`;
                     h += `</div>`;
                 }
                 $(el_window).find('.window-body').html(h);
@@ -105,7 +105,7 @@ async function UIWindowMyWebsites(options){
                 margin-bottom: 50px;
                 -webkit-font-smoothing: antialiased;
                 -moz-osx-font-smoothing: grayscale;
-                color: #596c7c;">You haven't published any websites!</p>`);
+                color: #596c7c;">${i18n('no_websites_published')}</p>`);
             }
         }, Date.now() - init_ts < 1000 ? 0 : 2000);
     })
@@ -136,10 +136,11 @@ $(document).on('click', '.mywebsites-site-setting', function(e){
                 html: `Release Address`,
                 onClick: async function(){
                     const alert_resp = await UIAlert({
-                        message: `Are you sure you want to release this address?`,
+                        message: i18n('release_address_confirmation'),
                         buttons:[
                             {
-                                label: 'Yes, Release It',
+                                label: i18n('yes_release_it'),
+                                value: 'yes',
                                 type: 'primary',
                             },
                             {
@@ -147,7 +148,7 @@ $(document).on('click', '.mywebsites-site-setting', function(e){
                             },
                         ]
                     })
-                    if(alert_resp !== 'Yes, Release It'){
+                    if(alert_resp !== 'yes'){
                         return;
                     }
                 

+ 1 - 1
src/UI/UIWindowNewFolderProgress.js

@@ -29,7 +29,7 @@ async function UIWindowNewFolderProgress(options){
             // message
             h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
                 // text
-                h += `<span class="newfolder-progress-msg">Taking a little longer than usual. Please wait...</span>`;
+                h += `<span class="newfolder-progress-msg">${i18n('taking_longer_than_usual')}</span>`;
             h += `</div>`;
         h +=`</div>`;
     h += `</div>`;

+ 3 - 3
src/UI/UIWindowNewPassword.js

@@ -34,17 +34,17 @@ async function UIWindowNewPassword(options){
             h += `<div class="form-success-msg"></div>`;
             // new password
             h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px;">`;
-                h += `<label for="new-password-${internal_id}">New Password</label>`;
+                h += `<label for="new-password-${internal_id}">${i18n('new_password')}</label>`;
                 h += `<input class="new-password" id="new-password-${internal_id}" type="password" name="new-password" autocomplete="off" />`;
             h += `</div>`;
             // confirm new password
             h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px;">`;
-                h += `<label for="confirm-new-password-${internal_id}">Confirm New Password</label>`;
+                h += `<label for="confirm-new-password-${internal_id}">${i18n('confirm_new_password')}</label>`;
                 h += `<input class="confirm-new-password" id="confirm-new-password-${internal_id}" type="password" name="confirm-new-password" autocomplete="off" />`;
             h += `</div>`;
 
             // Change Password
-            h += `<button class="change-password-btn button button-primary button-block button-normal">Set New Password</button>`;
+            h += `<button class="change-password-btn button button-primary button-block button-normal">${i18n('set_new_password')}</button>`;
         h += `</div>`;
 
         const el_window = await UIWindow({

+ 2 - 2
src/UI/UIWindowProgressEmptyTrash.js

@@ -29,13 +29,13 @@ async function UIWindowProgressEmptyTrash(options){
             // message
             h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
                 // text
-                h += `<span class="newfolder-progress-msg">Emptying the Trash...</span>`;
+                h += `<span class="newfolder-progress-msg">${i18n('emptying_trash')}</span>`;
             h += `</div>`;
         h +=`</div>`;
     h += `</div>`;
 
     const el_window = await UIWindow({
-        title: `Creating New Folder`,
+        title: i18n('emptying_trash'),
         icon: window.icons[`app-icon-newfolder.svg`],
         uid: null,
         is_dir: false,

+ 3 - 3
src/UI/UIWindowPublishWebsite.js

@@ -26,7 +26,7 @@ async function UIWindowPublishWebsite(target_dir_uid, target_dir_name, target_di
         // success
         h += `<div class="window-publishWebsite-success">`;
             h += `<img src="${html_encode(window.icons['c-check.svg'])}" style="width:80px; height:80px; display: block; margin:10px auto;">`;
-            h += `<p style="text-align:center;"><strong>${target_dir_name}</strong> has been published to:<p>`;
+            h += `<p style="text-align:center;">${i18n('dir_published_as_website', `<strong>${target_dir_name}</strong>`)}<p>`;
             h += `<p style="text-align:center;"><a class="publishWebsite-published-link" target="_blank"></a><img class="publishWebsite-published-link-icon" src="${html_encode(window.icons['launch.svg'])}"></p>`;
             h += `<button class="button button-normal button-block button-primary publish-window-ok-btn" style="margin-top:20px;">OK</button>`;
         h+= `</div>`;
@@ -36,13 +36,13 @@ async function UIWindowPublishWebsite(target_dir_uid, target_dir_name, target_di
             h += `<div class="publish-website-error-msg"></div>`;
             // subdomain
             h += `<div style="overflow: hidden;">`;
-                h += `<label style="margin-bottom: 10px;">Pick a name for your website:</label>`;
+                h += `<label style="margin-bottom: 10px;">${i18n('pick_name_for_website')}</label>`;
                 h += `<div style="font-family: monospace;">https://<input class="publish-website-subdomain" style="width:235px;" type="text" autocomplete="subdomain" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false"/>.${window.hosting_domain}</div>`;
             h += `</div>`;
             // uid
             h += `<input class="publishWebsiteTargetDirUID" type="hidden" value="${target_dir_uid}"/>`;
             // Publish
-            h += `<button class="publish-btn button button-action button-block button-normal">Publish</button>`
+            h += `<button class="publish-btn button button-action button-block button-normal">${i18n('publish')}</button>`
         h += `</form>`;
     h += `</div>`;
 

+ 1 - 1
src/UI/UIWindowQR.js

@@ -27,7 +27,7 @@ async function UIWindowQR(options){
         // close button containing the multiplication sign
         h += `<div class="qr-code-window-close-btn generic-close-window-button"> &times; </div>`;
         h += `<div class="otp-qr-code">`;
-            h += `<h1 style="text-align: center; font-size: 16px; padding: 10px; font-weight: 400; margin: -10px 10px 20px 10px; -webkit-font-smoothing: antialiased; color: #5f626d;">Scan the code below to log into this session from other devices</h1>`;
+            h += `<h1 style="text-align: center; font-size: 16px; padding: 10px; font-weight: 400; margin: -10px 10px 20px 10px; -webkit-font-smoothing: antialiased; color: #5f626d;">${i18n('scan_qr_c2a')}</h1>`;
         h += `</div>`;
 
         const el_window = await UIWindow({

+ 3 - 3
src/UI/UIWindowRecoverPassword.js

@@ -26,13 +26,13 @@ function UIWindowRecoverPassword(options){
 
         let h = '';
         h += `<div style="-webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #3e5362;">`;
-            h += `<h3 style="text-align:center; font-weight: 400; font-size: 20px;">Recover Password</h3>`;
+            h += `<h3 style="text-align:center; font-weight: 400; font-size: 20px;">${i18n('recover_password')}</h3>`;
             h += `<form class="pass-recovery-form">`;
                 h += `<p style="text-align:center; padding: 0 20px;"></p>`;
                 h += `<div class="error"></div>`;
-                h += `<label>Email or Username</label>`;
+                h += `<label>${i18n('email_or_username')}</label>`;
                 h += `<input class="pass-recovery-username-or-email" type="text"/>`;
-                h += `<button type="submit" class="send-recovery-email button button-block button-primary" style="margin-top:10px;">Send Recovery Email</button>`;
+                h += `<button type="submit" class="send-recovery-email button button-block button-primary" style="margin-top:10px;">${i18n('send_password_recovery_email')}</button>`;
             h += `</form>`;
         h += `</div>`;
 

+ 4 - 4
src/UI/UIWindowRefer.js

@@ -29,8 +29,8 @@ async function UIWindowRefer(options){
     h += `<div>`;
         h += `<div class="qr-code-window-close-btn generic-close-window-button disable-user-select"> &times; </div>`;
         h += `<img src="${window.icons['present.svg']}" style="width: 70px; margin: 20px auto 20px; display: block; margin-bottom: 20px;">`;
-        h += `<p style="text-align: center; font-size: 16px; padding: 20px; font-weight: 400; margin: -10px 10px 20px 10px; -webkit-font-smoothing: antialiased; color: #5f626d;">Get 1 GB for every friend who creates and confirms an account on Puter. Your friend will get 1 GB too!</p>`;
-        h += `<label style="font-weight: bold;">Invite link</label>`;
+        h += `<p style="text-align: center; font-size: 16px; padding: 20px; font-weight: 400; margin: -10px 10px 20px 10px; -webkit-font-smoothing: antialiased; color: #5f626d;">${i18n('refer_friends_c2a')}</p>`;
+        h += `<label style="font-weight: bold;">${i18n('invite_link')}</label>`;
         h += `<input type="text" style="margin-bottom:10px;" class="downloadable-link" readonly />`;
         h += `<button class="button button-primary copy-downloadable-link" style="width:130px;">${copy_btn_text}</button>`
         h += `<img class="share-copy-link-on-social" src="${window.icons['share-outline.svg']}">`;
@@ -72,11 +72,11 @@ async function UIWindowRefer(options){
     $(el_window).find('.window-body .downloadable-link').val(url);
 
     $(el_window).find('.window-body .share-copy-link-on-social').on('click', function(e){    
-        const social_links = socialLink({url: url, title: `Get 1 GB of free storage on Puter.com!`, description: `Get 1 GB of free storage on Puter.com!`});
+        const social_links = socialLink({url: url, title: i18n('refer_friends_social_media_c2a'), description: i18n('refer_friends_social_media_c2a')});
 
         let social_links_html = ``;
         social_links_html += `<div style="padding: 10px;">`;
-            social_links_html += `<p style="margin: 0; text-align: center; margin-bottom: 6px; color: #484a57; font-weight: bold; font-size: 14px;">Share to</p>`
+            social_links_html += `<p style="margin: 0; text-align: center; margin-bottom: 6px; color: #484a57; font-weight: bold; font-size: 14px;">${i18n('share_to')}</p>`
             social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.twitter}" style=""><svg viewBox="0 0 24 24" aria-hidden="true" style="opacity: 0.7;"><g><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg></a>`
             social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.whatsapp}" style=""><img src="${window.icons['logo-whatsapp.svg']}"></a>`
             social_links_html += `<a class="copy-link-social-btn" target="_blank" href="${social_links.facebook}" style=""><img src="${window.icons['logo-facebook.svg']}"></a>`

+ 8 - 8
src/UI/UIWindowSaveAccount.js

@@ -32,39 +32,39 @@ async function UIWindowSaveAccount(options){
             // success
             h += `<div class="save-account-success">`;
                 h += `<img src="${html_encode(window.icons['c-check.svg'])}" style="width:50px; height:50px; display: block; margin:10px auto;">`;
-                h += `<p style="text-align:center; margin-bottom:10px;">Thank you for creating an account. This session has been saved.</p>`;
-                h += `<button class="button button-action button-block save-account-success-ok-btn">OK</button>`
+                h += `<p style="text-align:center; margin-bottom:10px;">${i18n('session_saved')}</p>`;
+                h += `<button class="button button-action button-block save-account-success-ok-btn">${i18n('ok')}</button>`
             h+= `</div>`;
     
             // form
             h += `<div class="save-account-form" style="padding: 20px; border-bottom: 1px solid #ced7e1; width: 100%; box-sizing: border-box;">`;
                 // title
-                h += `<h1 class="signup-form-title" style="margin-bottom:0;">Create Account</h1>`;
+                h += `<h1 class="signup-form-title" style="margin-bottom:0;">${i18n('create_account')}</h1>`;
                 // description
-                h += `<p class="create-account-desc">${options.message ?? 'Create an account to save your current session and avoid losing your work.'}</p>`;
+                h += `<p class="create-account-desc">${options.message ?? i18n('save_session_c2a')}</p>`;
                 // signup form
                 h += `<form class="signup-form">`;
                     // error msg
                     h += `<div class="signup-error-msg"></div>`;
                     // username
                     h += `<div style="overflow: hidden;">`;
-                        h += `<label for="username-${internal_id}">Username</label>`;
+                        h += `<label for="username-${internal_id}">${i18n('username')}</label>`;
                         h += `<input id="username-${internal_id}" class="username" value="${options.default_username ?? ''}" type="text" autocomplete="username" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false"/>`;
                     h += `</div>`;
                     // email
                     h += `<div style="overflow: hidden; margin-top: 20px;">`;
-                        h += `<label for="email-${internal_id}">Email</label>`;
+                        h += `<label for="email-${internal_id}">${i18n('email')}</label>`;
                         h += `<input id="email-${internal_id}" class="email" type="email" autocomplete="email" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false"/>`;
                     h += `</div>`;
                     // password
                     h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px;">`;
-                        h += `<label for="password-${internal_id}">Password</label>`;
+                        h += `<label for="password-${internal_id}">${i18n('password')}</label>`;
                         h += `<input id="password-${internal_id}" class="password" type="password" name="password" autocomplete="new-password" />`;
                     h += `</div>`;
                     // bot trap - if this value is submitted server will ignore the request
                     h += `<input type="text" name="p102xyzname" class="p102xyzname" value="">`;
                     // Create Account
-                    h += `<button class="signup-btn button button-primary button-block button-normal">Create Account</button>`
+                    h += `<button class="signup-btn button button-primary button-block button-normal">${i18n('create_account')}</button>`
                 h += `</form>`;
             h += `</div>`;
         h += `</div>`;

+ 3 - 3
src/UI/UIWindowSessionList.js

@@ -28,16 +28,16 @@ async function UIWindowSessionList(options){
     return new Promise(async (resolve) => {
         let h = '';
         h += `<div style="margin:10px;">`;
-            h += `<div class="loading">Signing in...</div>`
+            h += `<div class="loading">${i18n('signing_in')}</div>`
             h += `<div style="overflow-y: scroll; max-width: 400px; margin: 0 auto;">`;
-            h += `<h1 style="text-align: center; font-size: 18px; font-weight: normal; color: #757575;"><img src="${icons['logo-white.svg']}" style="padding: 4px; background-color: blue; border-radius: 5px; width: 25px; box-sizing: border-box; margin-bottom: -6px; margin-right: 6px;">Sign in with Puter</h1>`
+            h += `<h1 style="text-align: center; font-size: 18px; font-weight: normal; color: #757575;"><img src="${icons['logo-white.svg']}" style="padding: 4px; background-color: blue; border-radius: 5px; width: 25px; box-sizing: border-box; margin-bottom: -6px; margin-right: 6px;">${i18n('sign_in_with_puter')}</h1>`
             for (let index = 0; index < logged_in_users.length; index++) {
                 const l_user = logged_in_users[index];
                 h += `<div data-uuid="${l_user.uuid}" class="session-entry">${l_user.username}</div>`;
             }
             h += `</div>`;
 
-            h += `<div style="margin-top: 20px; margin-bottom: 20px; text-align:center;"><span class="login-c2a-session-list">Log Into Another Account</span> &bull; <span class="signup-c2a-session-list">Create Account</span></div>`;
+            h += `<div style="margin-top: 20px; margin-bottom: 20px; text-align:center;"><span class="login-c2a-session-list">Log Into Another Account</span> &bull; <span class="signup-c2a-session-list">${i18n('create_account')}</span></div>`;
         h += `</div>`;
 
         const el_window = await UIWindow({

+ 7 - 7
src/UI/UIWindowSignup.js

@@ -40,39 +40,39 @@ function UIWindowSignup(options){
             // Form
             h += `<div style="padding: 20px; border-bottom: 1px solid #ced7e1;">`;
                 // title
-                h += `<h1 class="signup-form-title">Create Free Account</h1>`;
+                h += `<h1 class="signup-form-title">${i18n('create_free_account')}</h1>`;
                 // signup form
                 h += `<form class="signup-form">`;
                     // error msg
                     h += `<div class="signup-error-msg"></div>`;
                     // username
                     h += `<div style="overflow: hidden;">`;
-                        h += `<label for="username-${internal_id}">Username</label>`;
+                        h += `<label for="username-${internal_id}">${i18n('username')}</label>`;
                         h += `<input id="username-${internal_id}" class="username" type="text" autocomplete="username" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false"/>`;
                     h += `</div>`;
                     // email
                     h += `<div style="overflow: hidden; margin-top: 20px;">`;
-                        h += `<label for="email-${internal_id}">Email</label>`;
+                        h += `<label for="email-${internal_id}">${i18n('email')}</label>`;
                         h += `<input id="email-${internal_id}" class="email" type="email" autocomplete="email" spellcheck="false" autocorrect="off" autocapitalize="off" data-gramm_editor="false"/>`;
                     h += `</div>`;
                     // password
                     h += `<div style="overflow: hidden; margin-top: 20px; margin-bottom: 20px;">`;
-                        h += `<label for="password-${internal_id}">Password</label>`;
+                        h += `<label for="password-${internal_id}">${i18n('password')}</label>`;
                         h += `<input id="password-${internal_id}" class="password" type="password" name="password" autocomplete="new-password" />`;
                     h += `</div>`;
                     // bot trap - if this value is submitted server will ignore the request
                     h += `<input type="text" name="p102xyzname" class="p102xyzname" value="">`;
 
                     // terms and privacy
-                    h += `<p class="signup-terms">By clicking 'Create Free Account' you agree to Puter's <a href="https://puter.com/terms" target="_blank">Terms of Service</a> and <a href="https://puter.com/privacy" target="_blank">Privacy Policy</a>.</p>`;
+                    h += `<p class="signup-terms">${i18n('tos_fineprint', false)}</p>`;
                     // Create Account
-                    h += `<button class="signup-btn button button-primary button-block button-normal">Create Free Account</button>`
+                    h += `<button class="signup-btn button button-primary button-block button-normal">${i18n('create_free_account')}</button>`
                 h += `</form>`;
             h += `</div>`;
             // login link
             // create account link
             h += `<div class="c2a-wrapper" style="padding:20px;">`;
-                h += `<button class="login-c2a-clickable">Log In</button>`;
+                h += `<button class="login-c2a-clickable">${i18n('log_in')}</button>`;
             h += `</div>`;
         h += `</div>`;
 

+ 3 - 3
src/UI/UIWindowUploadProgress.js

@@ -29,19 +29,19 @@ async function UIWindowUploadProgress(options){
             // Progress report
             h +=`<div style="margin-bottom:20px; float:left; padding-top:3px; font-size:15px; overflow: hidden; width: calc(100% - 40px); text-overflow: ellipsis; white-space: nowrap;">`;
                 // msg
-                h += `<span class="upload-progress-msg">Preparing for upload...</span>`;
+                h += `<span class="upload-progress-msg">${i18n('preparing_for_upload')}</span>`;
             h += `</div>`;
             // progress
             h += `<div class="upload-progress-bar-container" style="clear:both; margin-top:20px; border-radius:3px;">`;
                 h += `<div class="upload-progress-bar"></div>`;
             h += `</div>`;
             // cancel
-            h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small upload-cancel-btn">Cancel</button>`;
+            h += `<button style="float:right; margin-top: 15px; margin-right: -2px;" class="button button-small upload-cancel-btn">${i18n('cancel')}</button>`;
         h +=`</div>`;
     h += `</div>`;
 
     const el_window = await UIWindow({
-        title: `Upload`,
+        title: i18n('Upload'),
         icon: window.icons[`app-icon-uploader.svg`],
         uid: null,
         is_dir: false,

+ 5 - 0
src/globals.js

@@ -96,6 +96,7 @@ try {
 if (window.user_preferences === null) {
     window.user_preferences = {
         show_hidden_files: false,
+        language: navigator.language.split("-")[0] || navigator.userLanguage || 'en',
     }
 }
 
@@ -199,3 +200,7 @@ window.feature_flags = {
     // if true, the user will be able to zip and download directories
     download_directory: true,
 }
+
+window.is_auto_arrange_enabled = true;
+window.desktop_item_positions = {};
+window.reset_item_positions = true; // The variable decides if the item positions should be reset when the user enabled auto arrange

+ 53 - 6
src/helpers.js

@@ -409,17 +409,17 @@ window.globToRegExp = function (glob, opts) {
  */
 window.validate_fsentry_name = function(name){
     if(!name)
-        throw {message: 'Name cannot be empty.'}
+        throw {message: i18n('name_cannot_be_empty')}
     else if(!isString(name))
-        throw {message: "Name can only be a string."}
+        throw {message: i18n('name_must_be_string')}
     else if(name.includes('/'))
-        throw {message: "Name cannot contain the '/' character."}
+        throw {message: i18n('name_cannot_contain_slash')}
     else if(name === '.')
-        throw {message: "Name can not be the '.' character."};
+        throw {message: i18n('name_cannot_contain_period')};
     else if(name === '..')
-        throw {message: "Name can not be the '..' character."};
+        throw {message: i18n('name_cannot_contain_double_period')};
     else if(name.length > window.max_item_name_length)
-        throw {message: `Name can not be longer than ${config.max_item_name_length} characters`}
+        throw {message: i18n('name_too_long', config.max_item_name_length)}
     else
         return true
 }
@@ -1295,6 +1295,7 @@ window.refresh_item_container = function(el_item_container, options){
                 if(item_path !== trash_path && item_path !== appdata_path){
                     // if this is trash, get original name from item metadata
                     fsentry.name = (metadata && metadata.original_name !== undefined) ? metadata.original_name : fsentry.name;
+                    const position = desktop_item_positions[fsentry.uid] ?? undefined;
                     UIItem({
                         appendTo: el_item_container,
                         uid: fsentry.uid,
@@ -1317,6 +1318,7 @@ window.refresh_item_container = function(el_item_container, options){
                         suggested_apps: fsentry.suggested_apps,
                         disabled: is_disabled,
                         visible: visible,
+                        position: position,
                     });
                 }
             }
@@ -3610,4 +3612,49 @@ window.get_html_element_from_options = async function(options){
     h += `</div>`;
 
     return h;
+}
+
+window.store_auto_arrange_preference = (preference)=>{
+    puter.kv.set('user_preferences.auto_arrange_desktop', preference);
+    localStorage.setItem('auto_arrange', preference);
+}
+
+window.get_auto_arrange_data = async()=>{
+    const preferenceValue = await puter.kv.get('user_preferences.auto_arrange_desktop');
+    is_auto_arrange_enabled = preferenceValue === null ? true : preferenceValue;
+    const positions = await puter.kv.get('desktop_item_positions')
+    desktop_item_positions =  (!positions || typeof positions !== 'object' || Array.isArray(positions)) ? {} : positions;
+}
+
+window.clear_desktop_item_positions = async(el_desktop)=>{
+    $(el_desktop).find('.item').each(function(){
+        const el_item = $(this)[0];
+        $(el_item).css('position', '');
+        $(el_item).css('left', '');
+        $(el_item).css('top', '');
+    });
+    if(reset_item_positions){
+        delete_desktop_item_positions()
+    }
+}
+
+window.set_desktop_item_positions = async(el_desktop)=>{
+    $(el_desktop).find('.item').each(async function(){
+        const position = desktop_item_positions[$(this).attr('data-uid')]
+        const el_item = $(this)[0];
+        if(position){
+            $(el_item).css('position', 'absolute');
+            $(el_item).css('left', position.left + 'px');
+            $(el_item).css('top', position.top + 'px');
+        }
+    });
+}
+
+window.save_desktop_item_positions = ()=>{
+    puter.kv.set('desktop_item_positions', desktop_item_positions);
+}
+
+window.delete_desktop_item_positions = ()=>{
+    desktop_item_positions = {}
+    puter.kv.del('desktop_item_positions');
 }

+ 5 - 5
src/helpers/new_context_menu_item.js

@@ -28,11 +28,11 @@
 
 const new_context_menu_item = function(dirname, append_to_element){
     return {
-        html: "New",
+        html: i18n('new'),
         items: [
             // New Folder
             {
-                html: "New Folder",
+                html: i18n('new_folder'),
                 icon: `<img src="${html_encode(window.icons['folder.svg'])}" class="ctx-item-icon">`,
                 onClick: function(){
                     create_folder(dirname, append_to_element);
@@ -42,7 +42,7 @@ const new_context_menu_item = function(dirname, append_to_element){
             '-',
             // Text Document
             {
-                html: `Text Document`,
+                html: i18n('text_document'),
                 icon: `<img src="${html_encode(window.icons['file-text.svg'])}" class="ctx-item-icon">`,
                 onClick: async function(){
                     create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.txt'});
@@ -50,7 +50,7 @@ const new_context_menu_item = function(dirname, append_to_element){
             },
             // HTML Document
             {
-                html: `HTML Document`,
+                html: i18n('html_document'),
                 icon: `<img src="${html_encode(window.icons['file-html.svg'])}" class="ctx-item-icon">`,
                 onClick: async function(){
                     create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.html'});
@@ -58,7 +58,7 @@ const new_context_menu_item = function(dirname, append_to_element){
             },
             // JPG Image
             {
-                html: `JPG Image`,
+                html: i18n('jpeg_image'),
                 icon: `<img src="${html_encode(window.icons['file-image.svg'])}" class="ctx-item-icon">`,
                 onClick: async function(){
                     var canvas = document.createElement("canvas");

+ 52 - 0
src/i18n/i18n.js

@@ -0,0 +1,52 @@
+import translations from './translations/translations.js';
+
+window.ListSupportedLanugages = () => Object.keys(translations).map(lang => translations[lang]);
+
+window.i18n = function (key, replacements = [], encode_html = true) {
+    if(typeof replacements === 'boolean' && encode_html === undefined){
+        encode_html = replacements;
+        replacements = [];
+    }else if(Array.isArray(replacements) === false){
+        replacements = [replacements];
+    }
+
+    // if locale is not set, default to en
+    if(!translations[window.locale])
+        window.locale = 'en';
+
+    let str = translations[window.locale].dictionary[key];
+    
+    if (!str) {
+        str = key;
+    }
+    str = encode_html ? html_encode(str) : str;
+    // replace %% occurrences with the values in replacements
+    // %% is for simple text replacements
+    // %strong% is for <strong> tags
+    // e.g. "Hello, %strong%" => "Hello, <strong>World</strong>"
+    // e.g. "Hello, %%" => "Hello, World"
+    // e.g. "Hello, %strong%, %%!" => "Hello, <strong>World</strong>, Universe!"
+    for (let i = 0; i < replacements.length; i++) {
+        // sanitize the replacement
+        replacements[i] = encode_html ? html_encode(replacements[i]) : replacements[i];
+        // find first occurrence of %strong%
+        let index = str.indexOf('%strong%');
+        // find first occurrence of %%
+        let index2 = str.indexOf('%%');
+        // decide which one to replace
+        if (index === -1 && index2 === -1) {
+            break;
+        } else if (index === -1) {
+            str = str.replace('%%', replacements[i]);
+        } else if (index2 === -1) {
+            str = str.replace('%strong%', '<strong>' + replacements[i] + '</strong>');
+        } else if (index < index2) {
+            str = str.replace('%strong%', '<strong>' + replacements[i] + '</strong>');
+        } else {
+            str = str.replace('%%', replacements[i]);
+        }
+    }
+    return str;
+}
+
+export default {};

+ 8 - 0
src/i18n/i18nChangeLanguage.js

@@ -0,0 +1,8 @@
+function ChangeLanguage(lang) {
+    window.locale = lang;
+    window.mutate_user_preferences({
+        language : lang,
+    });
+}
+
+export default ChangeLanguage;

+ 147 - 0
src/i18n/translations/bn.js

@@ -0,0 +1,147 @@
+const bn = {
+    name: "বাংলা",
+    code: "bn",
+    dictionary: {
+        access_granted_to: "অ্যাক্সেস মঞ্জুর করা হয়েছে",
+        add_existing_account: "আগে থাকা একাউন্ট অ্যাড করুন",
+        all_fields_required: 'সমস্ত ক্ষেত্র প্রয়োজন.',
+        apply: "আবেদন করুন",
+        ascending: 'উদীয়মান',
+        background: "পটভূমি",
+        browse: "ব্রাউজ করুন",
+        cancel: 'বাতিল করুন',
+        center: 'কেন্দ্র',
+        change_desktop_background: 'ডেস্কটপ পটভূমি পরিবর্তন করুন...',
+        change_password: "পাসওয়ার্ড পরিবর্তন করুন",
+        change_username: "ব্যবহারকারীর নাম পরিবর্তন করুন",
+        close_all_windows: "সমস্ত উইন্ডোজ বন্ধ করুন",
+        color: 'রঙ',
+        confirm_account_for_free_referral_storage_c2a: 'একটি অ্যাকাউন্ট তৈরি করুন এবং 1 GB বিনামূল্যে সঞ্চয়স্থান পেতে আপনার ইমেল ঠিকানা নিশ্চিত করুন৷ আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবে।',
+        confirm_new_password: "নিশ্চিত কর নতুন পাসওয়ার্ড",
+        contact_us: "আমাদের সাথে যোগাযোগ করুন",
+        contain: 'ধারণ করে',
+        continue: "চালিয়ে যান",
+        copy: 'কপি',
+        copy_link: "লিংক কপি করুন",
+        copying: "কপি করা হচ্ছে",
+        cover: 'আবরণ',
+        create_account: "একাউন্ট তৈরি করুন",
+        create_free_account: "ফ্রি একাউন্ট তৈরি করুন",
+        create_shortcut: "শর্টকাট তৈরি করুন",
+        current_password: "বর্তমান পাসওয়ার্ড",
+        cut: 'কাট',
+        date_modified: 'তারিখ পরিবর্তন করা হয়েছে',
+        delete: 'মুছে ফেলা',
+        delete_permanently: "চিরতরে মুছে দাও",
+        deploy_as_app: 'অ্যাপ হিসাবে স্থাপন করুন',
+        descending: 'অধোগামী',
+        desktop_background_fit: "ফিট",
+        dir_published_as_website: `%strong% এতে প্রকাশিত হয়েছে:`,
+        disassociate_dir: "ডিসঅ্যাসোসিয়েট ডিরেক্টরি",
+        download: 'ডাউনলোড করুন',
+        downloading: "ডাউনলোড হচ্ছে",
+        email: "ইমেইল",
+        email_or_username: "ইমেল বা ব্যবহারকারীর নাম",
+        empty_trash: 'ট্র্যাশ খালি',
+        empty_trash_confirmation: `আপনি কি ট্র্যাশে থাকা আইটেমগুলিকে স্থায়ীভাবে মুছে দেওয়ার বিষয়ে নিশ্চিত?`,
+        emptying_trash: 'ট্র্যাশ খালি করা হচ্ছে...',
+        feedback: "প্রতিক্রিয়া",
+        feedback_c2a: "আমাদের আপনার প্রতিক্রিয়া, মন্তব্য, এবং বাগ রিপোর্ট পাঠাতে নীচের ফর্ম ব্যবহার করুন.",
+        feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য আপনাকে ধন্যবাদ। আপনার অ্যাকাউন্টের সাথে যুক্ত কোনো ইমেল থাকলে, আপনি যত তাড়াতাড়ি সম্ভব আমাদের কাছ থেকে ফিরে পাবেন।",
+        forgot_pass_c2a: "পাসওয়ার্ড ভুলে গেছেন?",
+        from: "থেকে",
+        general: "সাধারণ",
+        get_a_copy_of_on_puter: `এর একটি কপি পান '%%' on Puter.com!`,
+        get_copy_link: 'অনুলিপি লিঙ্ক পান',
+        hide_all_windows: "সমস্ত উইন্ডোজ লুকান",
+        html_document: 'HTML নথি',
+        image: 'ছবি',
+        invite_link: "আমন্ত্রণ লিঙ্ক",
+        items_in_trash_cannot_be_renamed: `এই আইটেমটির নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে৷ এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটিকে ট্র্যাশ থেকে টেনে আনুন৷`,
+        jpeg_image: 'JPEG ছবি',
+        keep_in_taskbar: 'টাস্কবারে রাখুন',
+        log_in: "প্রবেশ করুন",
+        log_out: 'প্রস্থান',
+        move: 'সরান',
+        moving: "চলন্ত",
+        my_websites: "আমার ওয়েবসাইট",
+        name: 'নাম',
+        name_cannot_be_empty: 'নাম খালি রাখা যাবে না।',
+        name_cannot_contain_double_period: "নাম '..' অক্ষর হতে পারে না।",
+        name_cannot_contain_period: "নাম হতে পারে না '.' চরিত্র",
+        name_cannot_contain_slash: "নামে '/' অক্ষর থাকতে পারে না।",
+        name_must_be_string: "নাম শুধুমাত্র একটি স্ট্রিং হতে পারে.",
+        name_too_long: `নাম %% অক্ষরের বেশি হতে পারে না।`,
+        new: 'নতুন',
+        new_folder: 'নতুন ফোল্ডার',
+        new_password: "নতুন পাসওয়ার্ড",
+        new_username: "নতুন ব্যবহারকারীর নাম",
+        no_dir_associated_with_site: 'এই ঠিকানার সাথে সম্পর্কিত কোন ডিরেক্টরি নেই।',
+        no_websites_published: "আপনি এখনও কোনো ওয়েবসাইট প্রকাশ করেননি.",
+        ok: 'ঠিক আছে',
+        open: "খোলা",
+        open_in_new_tab: "নতুন ট্যাবে খুলুন",
+        open_in_new_window: "নতুন উইন্ডোতে খুলুন",
+        open_with: "সঙ্গে খোলা",
+        password: "পাসওয়ার্ড",
+        password_changed: "পাসওয়ার্ড পরিবর্তন.",
+        passwords_do_not_match: '`নতুন পাসওয়ার্ড` এবং `নিউ পাসওয়ার্ড নিশ্চিত করুন` মিলছে না।',
+        paste: 'পেস্ট করুন',
+        paste_into_folder: "ফোল্ডার আয়ে পেস্ট করুন",
+        pick_name_for_website: "আপনার ওয়েবসাইটের জন্য একটি নাম পছন্দ করুন:",
+        picture: "ছবি",
+        powered_by_puter_js: `দ্বারা চালিত <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "প্রস্তুত হচ্ছে...",
+        preparing_for_upload: "আপলোডের জন্য প্রস্তুত হচ্ছে...",
+        properties: "বৈশিষ্ট্য",
+        publish: "প্রকাশ করুন",
+        publish_as_website: 'ওয়েবসাইট হিসাবে প্রকাশ করুন',
+        recent: "সাম্প্রতিক",
+        recover_password: "পাসওয়ার্ড রিকভার করুন",
+        refer_friends_c2a: "Puter-এ অ্যাকাউন্ট তৈরি এবং নিশ্চিত করা প্রত্যেক বন্ধুর জন্য 1 GB পান। আপনার বন্ধুও পাবেন 1 জিবি!",
+        refer_friends_social_media_c2a: `1 GB বিনামূল্যে সঞ্চয়স্থান পান Puter.com এ!`,
+        refresh: 'রিফ্রেশ',
+        release_address_confirmation: `আপনি কি এই ঠিকানাটি প্রকাশ করার বিষয়ে নিশ্চিত?`,
+        remove_from_taskbar:'টাস্কবার থেকে সরান',
+        rename: 'নাম পরিবর্তন করুন',
+        repeat: 'রিপিট করুন',
+        resend_confirmation_code: "কনফার্মেশন কোড আবার পাঠান",
+        restore: "পুনরুদ্ধার করুন",
+        save_account_to_get_copy_link: "এগিয়ে যেতে একটি অ্যাকাউন্ট তৈরি করুন.",
+        save_account_to_publish: 'এগিয়ে যেতে একটি অ্যাকাউন্ট তৈরি করুন.',
+        save_session_c2a: 'আপনার বর্তমান সেশন সংরক্ষণ করতে এবং আপনার কাজ হারানো এড়াতে একটি অ্যাকাউন্ট তৈরি করুন।',
+        scan_qr_c2a: 'অন্যান্য ডিভাইস থেকে এই সেশনে লগ ইন করতে নিচের কোডটি স্ক্যান করুন',
+        select: "নির্বাচন করুন",
+        select_color: 'রঙ নির্বাচন করুন...',
+        send: "পাঠান",
+        send_password_recovery_email: "পাসওয়ার্ড পুনরুদ্ধার ইমেল পাঠান",
+        session_saved: "একটি অ্যাকাউন্ট তৈরি করার জন্য আপনাকে ধন্যবাদ. এই অধিবেশন সংরক্ষণ করা হয়েছে.",
+        set_new_password: "নতুন পাসওয়ার্ড সেট করুন",
+        share_to: "শেয়ার করুন",
+        show_all_windows: "সমস্ত উইন্ডোজ দেখান",
+        show_hidden: 'লুকোনো জিনিষ দেখাও',
+        sign_in_with_puter: "Puter দিয়ে সাইন ইন করুন",
+        sign_up: "নিবন্ধন করুন",
+        signing_in: "সাইন ইন…",
+        size: 'আকার',
+        sort_by: 'ক্রমানুসার',
+        start: 'শুরু করুন',
+        taking_longer_than_usual: 'স্বাভাবিকের চেয়ে একটু বেশি সময় নিচ্ছে। অনুগ্রহপূর্বক অপেক্ষা করুন...',
+        text_document: 'পাঠ্য নথি',
+        tos_fineprint: `'ফ্রি অ্যাকাউন্ট তৈরি করুন'-এ ক্লিক করার মাধ্যমে আপনি Puter-এর <a href="https://puter.com/terms" target="_blank">পরিষেবার শর্তাবলী</a> এবং <a href="https://puter-এর সাথে সম্মত হন .com/privacy" target="_blank">গোপনীয়তা নীতি</a>।`,
+        trash: 'আবর্জনা',
+        type: 'টাইপ',
+        undo: 'পূর্বাবস্থায় ফেরান',
+        unzip: "আনজিপ করুন",
+        upload: 'আপলোড করুন',
+        upload_here: 'এখানে আপলোড করুন',
+        username: "ব্যবহারকারীর নাম",
+        username_changed: 'ব্যবহারকারীর নাম সফলভাবে আপডেট করা হয়েছে।',
+        versions: "সংস্করণ",
+        yes_release_it: 'হ্যাঁ, এটা ছেড়ে দিন',
+        you_have_been_referred_to_puter_by_a_friend: "আপনি একজন বন্ধু দ্বারা Puter উল্লেখ করা হয়েছে!",
+        zip: "জিপ"
+    }
+}
+
+export default bn;

+ 148 - 0
src/i18n/translations/da.js

@@ -0,0 +1,148 @@
+const da = {
+    name: "Dansk",
+    code: "da",
+    dictionary: {
+        access_granted_to: "Adgang givet til",
+        add_existing_account: "Tilføj eksisterende konto",
+        all_fields_required: "Alle felter er obligatoriske.",
+        apply: "Anvend",
+        ascending: "Stigende",
+        background: "Baggrund",
+        browse: "Gennemse",
+        cancel: "Annuller",
+        center: "Centrer",
+        change_desktop_background: "Skift skrivebordsbaggrund…",
+        change_language: "Skift sprog",
+        change_password: "Skift adgangskode",
+        change_username: "Skift brugernavn",
+        close_all_windows: "Luk alle vinduer",
+        color: "Farve",
+        confirm_account_for_free_referral_storage_c2a: "Opret en konto og bekræft din e-mailadresse for at modtage 1 GB gratis lagerplads. Din ven får også 1 GB gratis lagerplads.",
+        confirm_new_password: "Bekræft ny adgangskode",
+        contact_us: "Kontakt os",
+        contain: "Indehold",
+        continue: "Fortsæt",
+        copy: "Kopier",
+        copy_link: "Kopier link",
+        copying: "Kopierer",
+        cover: "Dæk",
+        create_account: "Opret konto",
+        create_free_account: "Opret gratis konto",
+        create_shortcut: "Opret genvej",
+        current_password: "Nuværende adgangskode",
+        cut: "Klip",
+        date_modified: "Ændringsdato",
+        delete: "Slet",
+        delete_permanently: "Slet permanent",
+        deploy_as_app: "Udrul som app",
+        descending: "Faldende",
+        desktop_background_fit: "Tilpas",
+        dir_published_as_website: "%strong% er offentliggjort på:",
+        disassociate_dir: "Fjern tilknytning fra mappe",
+        download: "Download",
+        downloading: "Downloader",
+        email: "E-mail",
+        email_or_username: "E-mail eller brugernavn",
+        empty_trash: "Tøm papirkurv",
+        empty_trash_confirmation: "Er du sikker på, at du vil slette alt i papirkurven permanent?",
+        emptying_trash: "Tømmer papirkurv…",
+        feedback: "Feedback",
+        feedback_c2a: "Brug venligst formularen nedenfor til at sende os din feedback, kommentarer og fejlrapporter.",
+        feedback_sent_confirmation: "Tak fordi du kontaktede os. Hvis du har en e-mail tilknyttet din konto, hører du fra os så hurtigt som muligt.",
+        forgot_pass_c2a: "Glemt adgangskode?",
+        from: "Fra",
+        general: "Generelt",
+        get_a_copy_of_on_puter: "Få en kopi af '%%' på Puter.com!",
+        get_copy_link: "Få kopilink",
+        hide_all_windows: "Skjul alle vinduer",
+        html_document: "HTML-dokument",
+        image: "Billede",
+        invite_link: "Invitationslink",
+        items_in_trash_cannot_be_renamed: "Dette emne kan ikke omdøbes, fordi det er i papirkurven. For at omdøbe dette emne, træk det først ud af papirkurven.",
+        jpeg_image: "JPEG-billede",
+        keep_in_taskbar: "Behold i proceslinjen",
+        log_in: "Log ind",
+        log_out: "Log ud",
+        move: "Flyt",
+        moving: "Flytter",
+        my_websites: "Mine websteder",
+        name: "Navn",
+        name_cannot_be_empty: "Navn kan ikke være tomt.",
+        name_cannot_contain_double_period: "Navn kan ikke indeholde '..'.",
+        name_cannot_contain_period: "Navn kan ikke indeholde '.'-tegnet.",
+        name_cannot_contain_slash: "Navn kan ikke indeholde '/'-tegnet.",
+        name_must_be_string: "Navn skal være en streng.",
+        name_too_long: "Navn kan ikke være længere end %% tegn.",
+        new: "Ny",
+        new_folder: "Ny mappe",
+        new_password: "Ny adgangskode",
+        new_username: "Nyt brugernavn",
+        no_dir_associated_with_site: "Ingen mappe er tilknyttet denne adresse.",
+        no_websites_published: "Du har ikke offentliggjort nogen websteder endnu.",
+        ok: "OK",
+        open: "Åbn",
+        open_in_new_tab: "Åbn i ny fane",
+        open_in_new_window: "Åbn i nyt vindue",
+        open_with: "Åbn med",
+        password: "Adgangskode",
+        password_changed: "Adgangskode ændret.",
+        passwords_do_not_match: "`Ny adgangskode` og `Bekræft ny adgangskode` stemmer ikke overens.",
+        paste: "Indsæt",
+        paste_into_folder: "Indsæt i mappe",
+        pick_name_for_website: "Vælg et navn til dit websted:",
+        picture: "Billede",
+        powered_by_puter_js: "Drevet af <a href=\"https://docs.puter.com/\" target=\"_blank\">Puter.js</a>",
+        preparing: "Forbereder...",
+        preparing_for_upload: "Forbereder upload...",
+        properties: "Egenskaber",
+        publish: "Offentliggør",
+        publish_as_website: "Offentliggør som websted",
+        recent: "Seneste",
+        recover_password: "Gendan adgangskode",
+        refer_friends_c2a: "Få 1 GB for hver ven, der opretter og bekræfter en konto på Puter. Din ven får også 1 GB.",
+        refer_friends_social_media_c2a: "Få 1 GB gratis lagerplads på Puter.com!",
+        refresh: "Opdater",
+        release_address_confirmation: "Er du sikker på, at du vil frigive denne adresse?",
+        remove_from_taskbar: "Fjern fra proceslinjen",
+        rename: "Omdøb",
+        repeat: "Gentag",
+        resend_confirmation_code: "Send bekræftelseskoden igen",
+        restore: "Gendan",
+        save_account_to_get_copy_link: "Opret venligst en konto for at fortsætte.",
+        save_account_to_publish: "Opret venligst en konto for at fortsætte.",
+        save_session_c2a: "Opret en konto for at gemme din nuværende session og undgå at miste dit arbejde.",
+        scan_qr_c2a: "Scan koden nedenfor for at logge ind på denne session fra andre enheder",
+        select: "Vælg",
+        select_color: "Vælg farve…",
+        send: "Send",
+        send_password_recovery_email: "Send e-mail til gendannelse af adgangskode",
+        session_saved: "Tak for at du oprettede en konto. Denne session er gemt.",
+        set_new_password: "Indstil ny adgangskode",
+        share_to: "Del til",
+        show_all_windows: "Vis alle vinduer",
+        show_hidden: "Vis skjulte",
+        sign_in_with_puter: "Log ind med Puter",
+        sign_up: "Tilmeld dig",
+        signing_in: "Logger ind…",
+        size: "Størrelse",
+        sort_by: "Sorter efter",
+        start: "Start",
+        taking_longer_than_usual: "Dette tager længere tid end sædvanligt. Vent venligst...",
+        text_document: "Tekstdokument",
+        tos_fineprint: "Ved at klikke på 'Opret gratis konto' accepterer du Puters <a href=\"https://puter.com/terms\" target=\"_blank\">servicevilkår</a> og <a href=\"https://puter.com/privacy\" target=\"_blank\">privatlivspolitik</a>.",
+        trash: "Papirkurv",
+        type: "Type",
+        undo: "Fortryd",
+        unzip: "Udpak",
+        upload: "Upload",
+        upload_here: "Upload her",
+        username: "Brugernavn",
+        username_changed: "Brugernavn opdateret.",
+        versions: "Versioner",
+        yes_release_it: "Ja, frigør den",
+        you_have_been_referred_to_puter_by_a_friend: "Du er blevet henvist til Puter af en ven!",
+        zip: "Zip"
+    }
+};
+
+export default da;

+ 148 - 0
src/i18n/translations/de.js

@@ -0,0 +1,148 @@
+const de = {
+    name: "Deutsch",
+    code: "de",
+    dictionary: {
+        access_granted_to: "Erlaubt zugriff auf",
+        add_existing_account: "Bestehenden Account hinzufügen",
+        all_fields_required: 'Alle felder müssen ausgefüllt werden.',
+        apply: "Anwenden",
+        ascending: 'Aufsteigend',
+        background: "Hintergrund",
+        browse: "Durchsuchen",
+        cancel: 'Abbrechen',
+        center: 'Mitte',
+        change_desktop_background: 'Desktophintergrundbild ändern…',
+        change_language: "Sprache ändern",
+        change_password: "Passwort ändern",
+        change_username: "Benutzername ändern",
+        close_all_windows: "Alle fenster schließen",
+        color: 'Farbe',
+        confirm_account_for_free_referral_storage_c2a: 'Erstellen Sie ein Konto und bestätigen Sie Ihre E-Mail-Adresse, um 1 GB kostenlosen Speicherplatz zu erhalten. Auch Ihr Freund erhält 1 GB kostenlosen Speicherplatz.',
+        confirm_new_password: "Neues Passwort bestätigen",
+        contact_us: "Kontaktiere uns",
+        contain: 'Füllen',
+        continue: "Weiter",
+        copy: 'Kopieren',
+        copy_link: "Link kopieren",
+        copying: "Kopiert",
+        cover: 'Abdecken',
+        create_account: "Account erstellen",
+        create_free_account: "Kostenlosen Account erstellen",
+        create_shortcut: "Verknüpfung erstellen",
+        current_password: "Aktuelles Passwort",
+        cut: 'Ausschneiden',
+        date_modified: 'Zuletzt geändert',
+        delete: 'Entfernen',
+        delete_permanently: "Permanent entfernen",
+        deploy_as_app: 'Als App bereitstellen',
+        descending: 'Herabsteigend',
+        desktop_background_fit: "Fit", //idk translation
+        dir_published_as_website: `%strong% Wurde veröffentlicht zu:`,
+        disassociate_dir: "Verzeichniss trennen",
+        download: 'Herunterladen',
+        downloading: "Lädt herunter",
+        email: "Email",
+        email_or_username: "Email oder Benutzername",
+        empty_trash: 'Papierkorb leeren',
+        empty_trash_confirmation: `Sind Sie sicher, dass Sie die Elemente im Papierkorb dauerhaft löschen möchten?`,
+        emptying_trash: 'Leert Papierkorb…',
+        feedback: "Feedback",
+        feedback_c2a: "Bitte verwenden Sie das untenstehende Formular, um uns Ihr Feedback, Ihre Kommentare und Fehlerberichte zu senden.",
+        feedback_sent_confirmation: "Danke, dass Sie uns kontaktiert haben. Wenn mit Ihrem Konto eine E-Mail-Adresse verknüpft ist, erhalten Sie so schnell wie möglich eine Rückmeldung von uns.",
+        forgot_pass_c2a: "Passwort vergessen?",
+        from: "Von",
+        general: "Allgemein",
+        get_a_copy_of_on_puter: `Bekomme eine Kopie von '%%' auf Puter.com!`,
+        get_copy_link: 'Holen Sie sich den Link zum Kopieren',
+        hide_all_windows: "Alle Fenster verstecken",
+        html_document: 'HTML-Dokument',
+        image: 'Bild',
+        invite_link: "Einladungslink",
+        items_in_trash_cannot_be_renamed: `Dieses Element kann nicht umbenannt werden, da es sich im Papierkorb befindet. Um dieses Element umzubenennen, ziehen Sie es zunächst aus dem Papierkorb.`,
+        jpeg_image: 'JPEG-Bild',
+        keep_in_taskbar: 'In der Taskleiste behalten',
+        log_in: "Einloggen",
+        log_out: 'Ausloggen',
+        move: 'Verschieben',
+        moving: "Verschiebt",
+        my_websites: "Meine Webseiten",
+        name: 'Name',
+        name_cannot_be_empty: 'Name kann nicht leer sein.',
+        name_cannot_contain_double_period: "Der Name kann nicht '..' sein.",
+        name_cannot_contain_period: "Der Name kann nicht '.' sein.",
+        name_cannot_contain_slash: "Der Name kann nicht '/' enthalten.",
+        name_must_be_string: "Name kann nur eine Zeichenfolge sein.",
+        name_too_long: `Der Name kann nicht länger als %% Zeichen sein.`,
+        new: 'Neu',
+        new_folder: 'Neuer Ordner',
+        new_password: "Neues Passwort",
+        new_username: "Neuer Benutzername",
+        no_dir_associated_with_site: 'Mit dieser Adresse ist kein Verzeichnis verknüpft.',
+        no_websites_published: "Sie haben noch keine Webseite veröffentlicht",
+        ok: 'OK',
+        open: "Öffnen",
+        open_in_new_tab: "Im neuen Tab öffnen",
+        open_in_new_window: "Im neuen Fenster öffnen",
+        open_with: "Öffnen mit",
+        password: "Passwort",
+        password_changed: "Passwort geändert.",
+        passwords_do_not_match: '`Neues Passwoer` und `Neues Passwort bestätigen` stimmen nicht überein.',
+        paste: 'Einfügen',
+        paste_into_folder: "In Ordner einfügen",
+        pick_name_for_website: "Wählen Sie einen Namen für Ihre Webseite:",
+        picture: "Bild",
+        powered_by_puter_js: `Betrieben von <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "Bereitet vor...",
+        preparing_for_upload: "Bereitet für das Hochladen vor...",
+        properties: "Einstellungen",
+        publish: "Veröffentlichen",
+        publish_as_website: 'Als Webseite veröffentlichen',
+        recent: "Kürzlich",
+        recover_password: "Passwort wiederherstellen",
+        refer_friends_c2a: "Erhalten Sie 1 GB für jeden Freund, der ein Account bei Puter erstellt und bestätigt. Ihr Freund bekommt auch 1 GB!",
+        refer_friends_social_media_c2a: `Erhalten Sie 1 GB kostenlosen Speicherplatz auf Puter.com!`,
+        refresh: 'Neu laden',
+        release_address_confirmation: `Sind Sie sicher, dass Sie diese Adresse freigeben möchten?`,
+        remove_from_taskbar:'Von Taskleiste entfernen',
+        rename: 'Unbenennen',
+        repeat: 'Wiederholen',
+        resend_confirmation_code: "Bestätigungscode erneut senden",
+        restore: "Wiederherstellen",
+        save_account_to_get_copy_link: "Bitte erstellen Sie ein Acccount, um fortzufahren.",
+        save_account_to_publish: 'Bitte erstellen Sie ein Acccount, um fortzufahren.',
+        save_session_c2a: 'Erstellen Sie ein Konto, um Ihre aktuelle Sitzung zu speichern und den Verlust Ihrer Arbeit zu vermeiden.',
+        scan_qr_c2a: 'Scannen Sie den folgenden Code, um sich von anderen Geräten aus bei dieser Sitzung anzumelden',
+        select: "Auswählen",
+        select_color: 'Farbe auswählen…',
+        send: "Senden",
+        send_password_recovery_email: "Senden Sie eine E-Mail zur Passwortwiederherstellung",
+        session_saved: "Vielen Dank, dass Sie ein Konto erstellt haben. Diese Sitzung wurde gespeichert.",
+        set_new_password: "Neues Passwort erstellen",
+        share_to: "Teilen mit",
+        show_all_windows: "Alle Fenster zeigen",
+        show_hidden: 'Zeige versteckte',
+        sign_in_with_puter: "Einloggen mit Puter",
+        sign_up: "Einloggen",
+        signing_in: "Loggt ein…",
+        size: 'Größe',
+        sort_by: 'Sotieren nach',
+        start: 'Start',
+        taking_longer_than_usual: 'Dauert etwas länger als gewöhnlich. Bitte warten...',
+        text_document: 'Textdokument',
+        tos_fineprint: `Indem Sie auf „Kostenloses Konto erstellen“ klicken, stimmen Sie den <a href="https://puter.com/terms" target="_blank">Nutzungsbedingungen</a> und der <a href="https://puter.com/privacy" target="_blank">Datenschutzerklärung</a> von Puter zu.`,
+        trash: 'Papierkorb',
+        type: 'Typ',
+        undo: 'Zurück',
+        unzip: "Entpacken",
+        upload: 'Hochladen',
+        upload_here: 'Hier hochladen',
+        username: "Benutzername",
+        username_changed: 'Benutzername erfolgreich geändert.',
+        versions: "Versionen",
+        yes_release_it: 'Ja, veröffentlichen',
+        you_have_been_referred_to_puter_by_a_friend: "Sie wurden von einem Freund an Puter verwiesen!",
+        zip: "Zip",
+    }
+};
+
+export default de;

+ 148 - 0
src/i18n/translations/en.js

@@ -0,0 +1,148 @@
+const en = {
+    name: "English",
+    code: "en",
+    dictionary: {
+        access_granted_to: "Access Granted To",
+        add_existing_account: "Add Existing Account",
+        all_fields_required: 'All fields are required.',
+        apply: "Apply",
+        ascending: 'Ascending',
+        background: "Background",
+        browse: "Browse",
+        cancel: 'Cancel',
+        center: 'Center',
+        change_desktop_background: 'Change desktop background…',
+        change_language: "Change Language",
+        change_password: "Change Password",
+        change_username: "Change Username",
+        close_all_windows: "Close All Windows",
+        color: 'Color',
+        confirm_account_for_free_referral_storage_c2a: 'Create an account and confirm your email address to receive 1 GB of free storage. Your friend will get 1 GB of free storage too.',
+        confirm_new_password: "Confirm New Password",
+        contact_us: "Contact Us",
+        contain: 'Contain',
+        continue: "Continue",
+        copy: 'Copy',
+        copy_link: "Copy Link",
+        copying: "Copying",
+        cover: 'Cover',
+        create_account: "Create Account",
+        create_free_account: "Create Free Account",
+        create_shortcut: "Create Shortcut",
+        current_password: "Current Password",
+        cut: 'Cut',
+        date_modified: 'Date modified',
+        delete: 'Delete',
+        delete_permanently: "Delete Permanently",
+        deploy_as_app: 'Deploy as app',
+        descending: 'Descending',
+        desktop_background_fit: "Fit",
+        dir_published_as_website: `%strong% has been published to:`,
+        disassociate_dir: "Disassociate Directory",
+        download: 'Download',
+        downloading: "Downloading",
+        email: "Email",
+        email_or_username: "Email or Username",
+        empty_trash: 'Empty Trash',
+        empty_trash_confirmation: `Are you sure you want to permanently delete the items in Trash?`,
+        emptying_trash: 'Emptying Trash…',
+        feedback: "Feedback",
+        feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.",
+        feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.",
+        forgot_pass_c2a: "Forgot password?",
+        from: "From",
+        general: "General",
+        get_a_copy_of_on_puter: `Get a copy of '%%' on Puter.com!`,
+        get_copy_link: 'Get Copy Link',
+        hide_all_windows: "Hide All Windows",
+        html_document: 'HTML document',
+        image: 'Image',
+        invite_link: "Invite Link",
+        items_in_trash_cannot_be_renamed: `This item can't be renamed because it's in the trash. To rename this item, first drag it out of the Trash.`,
+        jpeg_image: 'JPEG image',
+        keep_in_taskbar: 'Keep in Taskbar',
+        log_in: "Log In",
+        log_out: 'Log Out',
+        move: 'Move',
+        moving: "Moving",
+        my_websites: "My Websites",
+        name: 'Name',
+        name_cannot_be_empty: 'Name cannot be empty.',
+        name_cannot_contain_double_period: "Name can not be the '..' character.",
+        name_cannot_contain_period: "Name can not be the '.' character.",
+        name_cannot_contain_slash: "Name cannot contain the '/' character.",
+        name_must_be_string: "Name can only be a string.",
+        name_too_long: `Name can not be longer than %% characters.`,
+        new: 'New',
+        new_folder: 'New folder',
+        new_password: "New Password",
+        new_username: "New Username",
+        no_dir_associated_with_site: 'No directory associated with this address.',
+        no_websites_published: "You have not published any websites yet.",
+        ok: 'OK',
+        open: "Open",
+        open_in_new_tab: "Open in New Tab",
+        open_in_new_window: "Open in New Window",
+        open_with: "Open With",
+        password: "Password",
+        password_changed: "Password changed.",
+        passwords_do_not_match: '`New Password` and `Confirm New Password` do not match.',
+        paste: 'Paste',
+        paste_into_folder: "Paste Into Folder",
+        pick_name_for_website: "Pick a name for your website:",
+        picture: "Picture",
+        powered_by_puter_js: `Powered by <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "Preparing...",
+        preparing_for_upload: "Preparing for upload...",
+        properties: "Properties",
+        publish: "Publish",
+        publish_as_website: 'Publish as website',
+        recent: "Recent",
+        recover_password: "Recover Password",
+        refer_friends_c2a: "Get 1 GB for every friend who creates and confirms an account on Puter. Your friend will get 1 GB too!",
+        refer_friends_social_media_c2a: `Get 1 GB of free storage on Puter.com!`,
+        refresh: 'Refresh',
+        release_address_confirmation: `Are you sure you want to release this address?`,
+        remove_from_taskbar:'Remove from Taskbar',
+        rename: 'Rename',
+        repeat: 'Repeat',
+        resend_confirmation_code: "Re-send Confirmation Code",
+        restore: "Restore",
+        save_account_to_get_copy_link: "Please create an account to proceed.",
+        save_account_to_publish: 'Please create an account to proceed.',
+        save_session_c2a: 'Create an account to save your current session and avoid losing your work.',
+        scan_qr_c2a: 'Scan the code below to log into this session from other devices',
+        select: "Select",
+        select_color: 'Select color…',
+        send: "Send",
+        send_password_recovery_email: "Send Password Recovery Email",
+        session_saved: "Thank you for creating an account. This session has been saved.",
+        set_new_password: "Set New Password",
+        share_to: "Share to",
+        show_all_windows: "Show All Windows",
+        show_hidden: 'Show hidden',
+        sign_in_with_puter: "Sign in with Puter",
+        sign_up: "Sign Up",
+        signing_in: "Signing in…",
+        size: 'Size',
+        sort_by: 'Sort by',
+        start: 'Start',
+        taking_longer_than_usual: 'Taking a little longer than usual. Please wait...',
+        text_document: 'Text document',
+        tos_fineprint: `By clicking 'Create Free Account' you agree to Puter's <a href="https://puter.com/terms" target="_blank">Terms of Service</a> and <a href="https://puter.com/privacy" target="_blank">Privacy Policy</a>.`,
+        trash: 'Trash',
+        type: 'Type',
+        undo: 'Undo',
+        unzip: "Unzip",
+        upload: 'Upload',
+        upload_here: 'Upload here',
+        username: "Username",
+        username_changed: 'Username updated successfully.',
+        versions: "Versions",
+        yes_release_it: 'Yes, Release It',
+        you_have_been_referred_to_puter_by_a_friend: "You have been referred to Puter by a friend!",
+        zip: "Zip",
+    }
+};
+
+export default en;

+ 148 - 0
src/i18n/translations/fa.js

@@ -0,0 +1,148 @@
+const fa = {
+    name: "فارسی",
+    code: "fa",
+    dictionary: {
+        access_granted_to: "دسترسی داده شده به",
+        add_existing_account: "افزودن حساب کاربری موجود",
+        all_fields_required: 'تمامی فیلدها الزامی هستند.',
+        apply: "اعمال",
+        ascending: 'صعودی',
+        background: "پس زمینه",
+        browse: "مرور",
+        cancel: 'لغو',
+        center: 'مرکز',
+        change_desktop_background: 'تغییر پس زمینه دسکتاپ…',
+        change_language: "تغییر زبان",
+        change_password: "تغییر رمز عبور",
+        change_username: "تغییر نام کاربری",
+        close_all_windows: "بستن همه پنجره ها",
+        color: 'رنگ',
+        confirm_account_for_free_referral_storage_c2a: 'حساب کاربری خود را ایجاد کرده و آدرس ایمیل خود را تأیید کنید تا 1 گیگابایت فضای ذخیره سازی رایگان دریافت کنید. دوست شما هم 1 گیگابایت فضای ذخیره سازی رایگان دریافت خواهد کرد.',
+        confirm_new_password: "تأیید رمز عبور جدید",
+        contact_us: "تماس با ما",
+        contain: 'شامل',
+        continue: "ادامه",
+        copy: 'کپی',
+        copy_link: "کپی لینک",
+        copying: "کپی",
+        cover: 'جلد',
+        create_account: "ایجاد حساب کاربری",
+        create_free_account: "ایجاد حساب کاربری رایگان",
+        create_shortcut: "ایجاد میانبر",
+        current_password: "رمز عبور فعلی",
+        cut: 'برش',
+        date_modified: 'تاریخ تغییر',
+        delete: 'حذف',
+        delete_permanently: "حذف دائمی",
+        deploy_as_app: 'نصب به عنوان برنامه',
+        descending: 'نزولی',
+        desktop_background_fit: "متناسب",
+        dir_published_as_website: `%strong% منتشر شده به:`,
+        disassociate_dir: "قطع ارتباط دایرکتوری",
+        download: 'دانلود',
+        downloading: "دانلود",
+        email: "ایمیل",
+        email_or_username: "ایمیل یا نام کاربری",
+        empty_trash: 'خالی کردن سطل زباله',
+        empty_trash_confirmation: `آیا از حذف دائمی موارد در سطل زباله مطمئن هستید؟`,
+        emptying_trash: 'خالی کردن سطل زباله…',
+        feedback: "بازخورد",
+        feedback_c2a: "لطفا از فرم زیر برای ارسال بازخورد، نظرات و گزارش خطا استفاده کنید.",
+        feedback_sent_confirmation: "با تشکر از تماس شما. اگر ایمیلی به حساب کاربری شما متصل است، در اسرع وقت پاسخ خواهیم داد.",
+        forgot_pass_c2a: "رمز عبور را فراموش کرده اید؟",
+        from: "از",
+        general: "عمومی",
+        get_a_copy_of_on_puter: `یک نسخه از '%%' را در Puter.com بگیرید!`,
+        get_copy_link: 'گرفتن لینک کپی',
+        hide_all_windows: "پنهان کردن همه پنجره ها",
+        html_document: 'سند HTML',
+        image: 'تصویر',
+        invite_link: "لینک دعوت",
+        items_in_trash_cannot_be_renamed: `این مورد نمی تواند تغییر نام دهد زیرا در سطل زباله است. برای تغییر نام این مورد، ابتدا آن را از سطل زباله بیرون بکشید.`,
+        jpeg_image: 'تصویر JPEG',
+        keep_in_taskbar: 'در نوار وظایف نگه دارید',
+        log_in: "ورود",
+        log_out: 'خروج',
+        move: 'انتقال',
+        moving: "انتقال",
+        my_websites: "وبسایت های من",
+        name: 'نام',
+        name_cannot_be_empty: 'نام نمی تواند خالی باشد.',
+        name_cannot_contain_double_period: "نام نمی تواند شامل '..' باشد.",
+        name_cannot_contain_period: "نام نمی تواند شامل '.' باشد.",
+        name_cannot_contain_slash: "نام نمی تواند شامل '/' باشد.",
+        name_must_be_string: "نام فقط می تواند یک رشته باشد.",
+        name_too_long: `نام نمی تواند بیشتر از %% کاراکتر باشد.`,
+        new: 'جدید',
+        new_folder: 'پوشه جدید',
+        new_password: "رمز عبور جدید",
+        new_username: "نام کاربری جدید",
+        no_dir_associated_with_site: 'هیچ دایرکتوری مرتبط با این آدرس وجود ندارد.',
+        no_websites_published: "هنوز هیچ وبسایتی منتشر نکرده اید.",
+        ok: 'خوب',
+        open: "باز کردن",
+        open_in_new_tab: "در تب جدید باز کن",
+        open_in_new_window: "در پنجره جدید باز کن",
+        open_with: "باز کردن با",
+        password: "رمز عبور",
+        password_changed: "رمز عبور تغییر یافت.",
+        passwords_do_not_match: '`رمز عبور جدید` و `تأیید رمز عبور جدید` مطابقت ندارند.',
+        paste: 'چسباندن',
+        paste_into_folder: "چسباندن در پوشه",
+        pick_name_for_website: "یک نام برای وبسایت خود انتخاب کنید:",
+        picture: "تصویر",
+        powered_by_puter_js: `پشتیبانی شده توسط <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "در حال آماده سازی...",
+        preparing_for_upload: "آماده سازی برای بارگذاری...",
+        properties: "ویژگی ها",
+        publish: "انتشار",
+        publish_as_website: 'انتشار به عنوان وبسایت',
+        recent: "اخیر",
+        recover_password: "بازیابی رمز عبور",
+        refer_friends_c2a: "برای هر دوستی که حساب کاربری Puter ایجاد و تأیید کند، 1 گیگابایت دریافت کنید. دوست شما هم 1 گیگابایت دریافت خواهد کرد!",
+        refer_friends_social_media_c2a: `1 گیگابایت فضای ذخیره سازی رایگان را در Puter.com بگیرید!`,
+        refresh: 'تازه کردن',
+        release_address_confirmation: `آیا مطمئن هستید که می خواهید این آدرس را آزاد کنید؟`,
+        remove_from_taskbar:'از نوار وظایف حذف کن',
+        rename: 'تغییر نام',
+        repeat: 'تکرار',
+        resend_confirmation_code: "ارسال مجدد کد تأیید",
+        restore: "بازیابی",
+        save_account_to_get_copy_link: "لطفا برای ادامه یک حساب کاربری ایجاد کنید.",
+        save_account_to_publish: 'لطفا برای ادامه یک حساب کاربری ایجاد کنید.',
+        save_session_c2a: 'برای ذخیره جلسه فعلی و جلوگیری از از دست دادن کار خود یک حساب کاربری ایجاد کنید.',
+        scan_qr_c2a: 'کد زیر را از دستگاه های دیگر اسکن کنید تا به این جلسه وارد شوید',
+        select: "انتخاب",
+        select_color: 'انتخاب رنگ…',
+        send: "ارسال",
+        send_password_recovery_email: "ارسال ایمیل بازیابی رمز عبور",
+        session_saved: "با تشکر از ایجاد حساب کاربری. این جلسه ذخیره شده است.",
+        set_new_password: "تنظیم رمز عبور جدید",
+        share_to: "اشتراک گذاری به",
+        show_all_windows: "نمایش همه پنجره ها",
+        show_hidden: 'نمایش مخفی',
+        sign_in_with_puter: "ورود با Puter",
+        sign_up: "ثبت نام",
+        signing_in: "ورود…",
+        size: 'اندازه',
+        sort_by: 'مرتب سازی بر اساس',
+        start: 'شروع',
+        taking_longer_than_usual: 'کمی بیشتر از معمول طول می کشد. لطفا صبر کنید...',
+        text_document: 'سند متنی',
+        tos_fineprint: `با کلیک بر روی 'ایجاد حساب کاربری رایگان' شما با <a href="https://puter.com/terms" target="_blank">شرایط خدمات</a> و <a href="https://puter.com/privacy" target="_blank">سیاست حفظ حریم خصوصی</a> Puter موافقت می کنید.`,
+        trash: 'سطل زباله',
+        type: 'نوع',
+        undo: 'بازگشت',
+        unzip: "باز کردن فایل فشرده",
+        upload: 'بارگذاری',
+        upload_here: 'اینجا بارگذاری کنید',
+        username: "نام کاربری",
+        username_changed: 'نام کاربری با موفقیت به روز شد.',
+        versions: "نسخه ها",
+        yes_release_it: 'بله، آن را آزاد کن',
+        you_have_been_referred_to_puter_by_a_friend: "شما توسط یک دوست به Puter معرفی شده اید!",
+        zip: "فشرده سازی",
+    }
+};
+
+export default fa;

+ 207 - 0
src/i18n/translations/fi.js

@@ -0,0 +1,207 @@
+const fi = {
+    name: "Suomi",
+    code: "fi",
+    dictionary: {
+        access_granted_to: "Käyttöoikeus Myönnetty",
+        add_existing_account: "Lisää Olemassaoleva Tili",
+        all_fields_required: 'Kaikki kentät on täytettävä.',
+
+        apply: "Apply", // TODO: Ambiguous meaning
+        // To apply(a principle) => "Sovella" or
+        // Apply for(a job) "Hae" or 
+        // Apply as(an engineer) => "Hakeudu" or
+        // Apply an expression => "Applikoi" or - Probably the most appropriate in the context of the app
+        // Apply in the sense of applying something, like a tool => "Käytä"
+
+        ascending: 'Nouseva',
+        background: "Tausta",
+        browse: "Selaa",
+        cancel: 'Peruuta',
+        center: 'Keskus',
+        change_desktop_background: 'Vaihda työpöydän taustakuvaa…',
+        change_password: "Muuta Salasana",
+        change_username: "Muuta Käyttäjänimeä",
+        close_all_windows: "Sulje Kaikki Ikkunat",
+        color: 'Väri',
+        confirm_account_for_free_referral_storage_c2a: 'Luo tili ja vahvista sähköpostiosoitteesi saadaksesi 1 Gt ilmaista tallennustilaa. Myös kaverisi saa 1 Gt ilmaista tallennustilaa.',
+        confirm_new_password: "Vahvista Uusi Salasana",
+        contact_us: "Ota Yhteyttä",
+
+        contain: 'Contain', // TODO: Ambiguous meaning
+        // "inside(a house)" => "Sisällä" - probably more appropriate
+        // "contain within" => "Sisältää"
+
+        continue: "Jatka",
+
+        copy: 'Copy', // TODO: Lexical categories
+        // Noun "A copy of something" => 'Kopio' or
+        // Verb "To copy something" => 'Kopioi'?
+
+        copy_link: "Kopioi Linkki",
+        copying: "Kopioidaan",
+
+        cover: 'Cover', // TODO: Lexical categories
+        // Noun (shelter) => 'Suoja' or 
+        // Noun (lid) => 'Kansi' or
+        // Intransitive Verb (To occlude something) => 'Peitä' or
+        // Transitive Verb (To cover for someone) => 'Suojaa'
+
+        create_account: "Luo Tili",
+        create_free_account: "Luo Ilmainen Tili",
+        create_shortcut: "Luo Pikakuvake",
+        current_password: "Nykyinen Salasana",
+        cut: 'Leikkaa',
+        date_modified: 'Muutospäivämäärä',
+        delete: 'Poista',
+        delete_permanently: "Poista Pysyvästi",
+        deploy_as_app: 'Levitä sovelluksena',
+        descending: 'Laskeva',
+        desktop_background_fit: "Sovita",
+        dir_published_as_website: `%strong% on julkaistu osoitteessa:`,
+        disassociate_dir: "Erota Hakemisto",
+        download: 'Lataa',
+        downloading: "Ladataan",
+        email: "Sähköposti",
+        email_or_username: "Sähköposti tai Käyttäjänimi",
+        empty_trash: 'Tyhjennä Roskakori',
+        empty_trash_confirmation: `Oletko varma, että haluat poistaa Roskakorin kohteet pysyvästi?`,
+        emptying_trash: 'Tyhjennetään Roskakori…',
+        feedback: "Palaute",
+        feedback_c2a: "Käytä alla olevaa lomaketta lähettääksesi meille palautetta, kommentteja ja vikailmoituksia.",
+        feedback_sent_confirmation: "Kiitos yhteydenotosta. Jos sinulla on tiliisi liittyvä sähköpostiosoite, saat meiltä vastauksen mahdollisimman pian.",
+        forgot_pass_c2a: "Unohditko Salasanasi?",
+
+        from: "From", // TODO: Context dependent, examples
+        // "from address" => "osoitteesta" or
+        // "from sender" => "lähettäjältä".
+        // In the finnish language these are usually translated as case suffixes.
+        // "From Person" gets the suffix "-ltä", being the combination of "Henkilö(Person) and ltä(From)"
+
+        general: "General", // TODO: Conceptual ambiguity
+        // "general (about something)" => "Yleistä" or
+        // "military general" => "Kenraali"
+
+        get_a_copy_of_on_puter: `Hanki '%%' -kopio Puter.com-sivustolta!`, // TODO: Very difficult ambiguity due to different case suffix for any possible word that you can substitue here. Can stay as is, but it's not exactly correct.
+
+        get_copy_link: 'Get Copy Link', // TODO: Ambiguous meaning
+        // 'get a copy of a link' => 'Ota Kopio Linkkiin' or
+        // 'get a link to the copy' => 'Ota Linkki Kopioon' - More probable, just want to be sure
+
+        hide_all_windows: "Piilota Kaikki Ikkunat",
+        html_document: 'HTML-dokumentti',
+        image: 'Kuva',
+        invite_link: "Kutsulinkki",
+        items_in_trash_cannot_be_renamed: `Tätä kohdetta ei voi nimetä uudelleen, koska se on roskakorissa. Jos haluat nimetä kohteen uudelleen, raahaa se ensin pois roskakorista.`,
+        jpeg_image: 'JPEG-kuva',
+        keep_in_taskbar: 'Pidä tehtäväpalkissa',
+        log_in: "Kirjaudu Sisään",
+        log_out: 'Kirjaudu Ulos',
+        move: 'Siirrä',
+        moving: "Siirretään",
+        my_websites: "Verkkosivustoni",
+        name: 'Nimi',
+        name_cannot_be_empty: 'Nimi ei voi olla tyhjä.',
+
+        name_cannot_contain_double_period: "Name can not be the '..' character.", // TODO: definition says a different thing, than the string
+        // "Name can not be the '..' character." => "Nimi ei voi olla '..'-merkki." or
+        // "Name can not contain the '..' character." => "Nimi ei voi sisältää merkkiä '..'."
+
+        name_cannot_contain_period: "Name can not be the '.' character.", // TODO: definition says a different thing, than the string
+        // "Name can not be the '.' character." => "Nimi ei voi olla '.'-merkki." or
+        // "Name can not contain the '.' character." => "Nimi ei voi sisältää merkkiä '.'."
+
+        name_cannot_contain_slash: "Nimi ei voi sisältää merkkiä '/'.",
+        name_must_be_string: "Nimi voi olla vain merkkijono.",
+        name_too_long: `Nimi ei voi olla pidempi kuin %% merkkiä.`,
+        new: 'Uusi',
+        new_folder: 'Uusi kansio',
+        new_password: "Uusi Salasana",
+        new_username: "Uusi Käyttäjänimi",
+        no_dir_associated_with_site: 'Osoitteeseen ei liity mitään hakemistoa.',
+        no_websites_published: "Et ole vielä julkaissut yhtään verkkosivustoa.",
+        ok: 'OK',
+        open: "Avaa",
+        open_in_new_tab: "Avaa uudessa Välilehdessä",
+        open_in_new_window: "Avaa uudessa Ikkunassa",
+
+        open_with: "Open With", // TODO: Context dependent
+        // "Open" => "Avaa", can be "Avaa..." in this context or
+        // "Open With" is often translated in the context of "Open With Application" => "Avaa Sovelluksessa"
+
+        password: "Salasana",
+        password_changed: "Salasana vaihdettu.",
+        passwords_do_not_match: '`Uusi Salasana` ja `Vahvista Uusi Salasana` eivät täsmää.',
+        paste: 'Liitä',
+        paste_into_folder: "Liitä Kansioon",
+        pick_name_for_website: "Valitse nimi verkkosivustollesi:",
+        picture: "Kuva",
+        powered_by_puter_js: `Tämän Mahdollistaa <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "Valmistellaan...",
+        preparing_for_upload: "Valmistellaan latausta...",
+        properties: "Ominaisuudet",
+        publish: "Julkaise",
+        publish_as_website: 'Julkaise verkkosivustona',
+        recent: "Viimeisimmät",
+        recover_password: "Palauta Salasana",
+        refer_friends_c2a: "Saat 1 Gt tilaa jokaisesta kaverista, joka luo ja vahvistaa tilin Puterissa. Myös kaverisi saa 1 Gt tilaa!",
+        refer_friends_social_media_c2a: `Hanki 1 Gt ilmaista tallennustilaa Puter.comista!`,
+        refresh: 'Päivitä',
+
+        release_address_confirmation: `Are you sure you want to release this address?`, // TODO: Slight ambiguity between the meaning of "release"
+        // "get rid of" => "Oletko varma, että haluat luovuttaa tämän osoitteen?" or
+        // "publish" => "Oletko varma, että haluat julkaista tämän osoitteen?"
+
+        remove_from_taskbar:'Poista Tehtäväpalkista',
+        rename: 'Nimeä uudelleen',
+        repeat: 'Toista',
+        resend_confirmation_code: "Lähetä Vahvistuskoodi Uudelleen",
+        restore: "Palauta",
+        save_account_to_get_copy_link: "Luo tili jatkaaksesi.",
+        save_account_to_publish: 'Luo tili jatkaaksesi.',
+        save_session_c2a: 'Luo tili tallentaaksesi nykyisen istuntosi ja välttyäksesi työn menettämiseltä.',
+        scan_qr_c2a: 'Skannaa alla oleva koodi kirjautuaksesi tähän istuntoon muista laitteista',
+        select: "Valitse",
+        select_color: 'Valitse väri…',
+        send: "Lähetä",
+        send_password_recovery_email: "Lähetä Salasanan Palautussähköposti",
+        session_saved: "Kiitos tilin luomisesta. Tämä istunto on tallennettu.",
+        set_new_password: "Aseta Uusi Salasana",
+
+        share_to: "Share to", // TODO: Grammatical ambiguity
+        // The base form of "Share" is "Jaa". So maybe "Jaa..." is appropriate?
+        // If "share to" is followed by the name of a user, it will not make any sense, as the name can be suffixed by for example "Jaa %%lle".
+
+        show_all_windows: "Näytä Kaikki Ikkunat",
+        show_hidden: 'Näytä piilotettu',
+        sign_in_with_puter: "Kirjaudu sisään Puterilla",
+        sign_up: "Rekisteröidy",
+        signing_in: "Kirjaudutaan sisään…",
+        size: 'Koko',
+        sort_by: 'Lajittele:',
+        start: 'Käynnistä',
+        taking_longer_than_usual: 'Kestää hieman tavallista kauemmin. Odottakaa...',
+        text_document: 'Tekstiasiakirja',
+        tos_fineprint: `Klikkaamalla 'Luo ilmainen tili' hyväksyt Puterin käyttöehdot ja tietosuojakäytännön.`,
+
+        trash: 'Trash', // TODO: Ambiguous meaning
+        // "Trash" is oft used to just mean "Trash bin" => 'Roskakori' or
+        // "Trash" by itself => 'Roska'
+
+        type: 'Type', // TODO: Ambiguous meaning
+        // "Type of an object" => 'Tyyppi' or
+        // "Type on the keyboard" => 'Kirjoita'
+
+        undo: 'Kumoa',
+        unzip: "Pura zip",
+        upload: 'Lataa',
+        upload_here: 'Lataa tähän',
+        username: "Käyttäjänimi",
+        username_changed: 'Käyttäjänimi päivitetty onnistuneesti.',
+        versions: "Versiot",
+        yes_release_it: 'Kyllä, Julkaise Se',
+        you_have_been_referred_to_puter_by_a_friend: "Kaverisi on kutsunut sinut Puterille!",
+        zip: "Zip",
+    }
+}
+
+export default fi;

+ 148 - 0
src/i18n/translations/fr.js

@@ -0,0 +1,148 @@
+const fr = {
+    name: "Français",
+    code: "fr",
+    dictionary: {
+        access_granted_to: "Accès accordé à",
+        add_existing_account: "Ajouter un compte existant",
+        all_fields_required: 'All fields are required.',
+        apply: "Appliquer",
+        ascending: 'Ascending',
+        background: "Background",
+        browse: "Browse",
+        cancel: 'Annuler',
+        center: 'Center',
+        change_desktop_background: 'Changer l’arrière-plan du bureau…',
+        change_language: "Changer de langue",
+        change_password: "Changer de mot de passe",
+        change_username: "Changer de nom d'ulilisateur",
+        close_all_windows: "Fermer toutes les fenêtres",
+        color: 'Couleur',
+        confirm_account_for_free_referral_storage_c2a: 'Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami bénéficiera également de 1 Go de stockage gratuit.',
+        confirm_new_password: "Confirmez le nouveau mot de passe",
+        contact_us: "Nous contacter",
+        contain: 'Contain',
+        continue: "Continuer",
+        copy: 'Copier',
+        copy_link: "Copier le lien",
+        copying: "Copying",
+        cover: 'Cover',
+        create_account: "Créer un compte",
+        create_free_account: "Créer un compte gratuit",
+        create_shortcut: "Créer un raccourci",
+        current_password: "Mot de passe actuel",
+        cut: 'Couper',
+        date_modified: 'Date de modification',
+        delete: 'Supprimer',
+        delete_permanently: "Supprimer définitivement",
+        deploy_as_app: 'Deployer en tant qu\'application',
+        descending: 'Décroissant',
+        desktop_background_fit: "Ajuster",
+        dir_published_as_website: `%strong% a été publié sur :`,
+        disassociate_dir: "Dissocier le répertoire",
+        download: 'Télécharger',
+        downloading: "Téléchargement en cours",
+        email: "Email",
+        email_or_username: "Email ou nom d'utilisateur",
+        empty_trash: 'Vider la corbeille',
+        empty_trash_confirmation: `Êtes-vous sûr de vouloir supprimer définitivement les éléments de la corbeille ?`,
+        emptying_trash: 'Vidage de la corbeille...',
+        feedback: "Envoyer des commentaires",
+        feedback_c2a: "Veuillez utiliser le formulaire ci-dessous pour nous envoyer vos retours, commentaires et rapports de bugs.",
+        feedback_sent_confirmation: "Merci de nous avoir contactés. Si vous avez un e-mail associé à votre compte, vous recevrez une réponse de notre part dans les plus brefs délais.",
+        forgot_pass_c2a: "Mot de passe oublier?",
+        from: "De",
+        general: "Général",
+        get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com!`,
+        get_copy_link: 'Obtenir le lien de copie',
+        hide_all_windows: "Masquer toutes les fenêtres",
+        html_document: 'Document HTML',
+        image: 'Image',
+        invite_link: "Lien d'invitation",
+        items_in_trash_cannot_be_renamed: `Cet élément ne peut pas être renommé car il se trouve dans la corbeille. Pour renommer cet élément, faites-le d'abord glisser hors de la corbeille.`,
+        jpeg_image: 'Image JPEG',
+        keep_in_taskbar: 'Garder dans la barre des tâches',
+        log_in: "Se connecter",
+        log_out: 'Déconnexion',
+        move: 'Déplacer',
+        moving: "Déplacement en cours",
+        my_websites: "Mes sites internet",
+        name: 'Nom',
+        name_cannot_be_empty: 'Le nom ne peut pas être vide.',
+        name_cannot_contain_double_period: "Le nom ne peut pas être le caractère '..'.",
+        name_cannot_contain_period: "Le nom ne peut pas être le caractère '.'.",
+        name_cannot_contain_slash: "Le nom ne peut pas contenir le caractère '/'.",
+        name_must_be_string: "Le nom peut uniquement être une chaîne.",
+        name_too_long: `Le nom ne peut pas contenir plus de %% caractères.`,
+        new: 'Nouveau',
+        new_folder: 'Nouveau dossier',
+        new_password: "Nouveau mot de passe",
+        new_username: "Nouveau nom d'utilisateur",
+        no_dir_associated_with_site: 'Aucun répertoire associé à cette adresse.',
+        no_websites_published: "Vous n'avez pas encore publié de sites internet.",
+        ok: 'OK',
+        open: "Ouvrir",
+        open_in_new_tab: "Ouvrir dans un nouvel onglet",
+        open_in_new_window: "Ouvrir dans une nouvelle fenêtre",
+        open_with: "Ouvrir avec",
+        password: "Mot de passe",
+        password_changed: "Mot de passe modifié.",
+        passwords_do_not_match: '\'Nouveau mot de passe\' et \'Confirmer le nouveau mot de passe\' ne correspondent pas.',
+        paste: 'Coller',
+        paste_into_folder: "Coller dans le dossier",
+        pick_name_for_website: "Choisissez un nom pour votre site Web :",
+        picture: "Image",
+        powered_by_puter_js: `Alimenté par <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "Préparation...",
+        preparing_for_upload: "Préparation du chargement...",
+        properties: "Propriétés",
+        publish: "Publier",
+        publish_as_website: 'Publier en tant que site internet',
+        recent: "Récent",
+        recover_password: "Récupérer le mot de passe",
+        refer_friends_c2a: "Obtenez 1 Go pour chaque ami qui crée et confirme un compte sur Puter. Votre ami recevra également 1 Go !",
+        refer_friends_social_media_c2a: `Obtenez 1 Go de stockage gratuit sur Puter.com !`,
+        refresh: 'Actualiser',
+        release_address_confirmation: `Êtes-vous sûr de vouloir libérer cette adresse ?`,
+        remove_from_taskbar:'Retirer de la barre des tâches',
+        rename: 'Renomer',
+        repeat: 'Répéter',
+        resend_confirmation_code: "Renvoyer le code de confirmation",
+        restore: "Restorer",
+        save_account_to_get_copy_link: "Veuillez créer un compte pour continuer",
+        save_account_to_publish: 'Veuillez créer un compte pour continuer.',
+        save_session_c2a: 'Créez un compte pour sauvegarder votre session en cours et éviter de perdre votre travail.',
+        scan_qr_c2a: 'Scannez le code ci-dessous pour vous connecter à cette session depuis d\'autres appareils',
+        select: "Sélectionner",
+        select_color: 'Sélectionner une couleur...',
+        send: "Envoyer",
+        send_password_recovery_email: "Envoyer un e-mail de récupération de mot de passe",
+        session_saved: "Merci d'avoir créé un compte. Cette session a été sauvegardée.",
+        set_new_password: "Definir un nouveau mot de passe",
+        share_to: "Partager à",
+        show_all_windows: "Afficher toutes les fenêtres",
+        show_hidden: 'Afficher les éléments cachés',
+        sign_in_with_puter: "Se connecter avec Puter",
+        sign_up: "S'inscrire",
+        signing_in: "Connexion…",
+        size: 'Taille',
+        sort_by: 'Trier par',
+        start: 'Démarrer',
+        taking_longer_than_usual: 'Cela prend un peu plus de temps que d\'habitude. Veuillez patienter...',
+        text_document: 'Document texte',
+        tos_fineprint: `En cliquant sur "Créer un compte gratuit", vous acceptez les <a href="https://puter.com/terms" target="_blank">conditions d'utilisation</a> et la <a href="https://puter .com/privacy" target="_blank">politique de confidentialité</a>.`,
+        trash: 'Corbeille',
+        type: 'Type',
+        undo: 'Annuler',
+        unzip: "Décompresser",
+        upload: 'Charger',
+        upload_here: 'Charger ici',
+        username: "Nom d'utilisateur",
+        username_changed: 'Nom d\'utilisateur mis à jour avec succès.',
+        versions: "Versions",
+        yes_release_it: 'Oui, libérez-la',
+        you_have_been_referred_to_puter_by_a_friend: "Vous avez été référé à Puter par un ami !",
+        zip: "Compresser",
+    }
+}
+
+export default fr;

+ 148 - 0
src/i18n/translations/it.js

@@ -0,0 +1,148 @@
+const it = {
+    name: "Italiano",
+    code: "it",
+    dictionary: {
+        access_granted_to: "Accesso garantito a",
+        add_existing_account: "Aggiungi un account esistente",
+        all_fields_required: 'Tutte le caselle sono richieste.',
+        apply: "Applica",
+        ascending: 'Ascendente',
+        background: "Sfondo",
+        browse: "Sfoglia",
+        cancel: 'Annulla',
+        center: 'Centra ',
+        change_desktop_background: 'Modifica sfondo…',
+        change_language: "Cambia lingua",
+        change_password: "Modifica password",
+        change_username: "Modifica Nome Utente",
+        close_all_windows: "Chiudi tutte le finestre",
+        color: 'Colore',
+        confirm_account_for_free_referral_storage_c2a: 'Crea un account e conferma la tua email per ricevere 1 GB di spazio di archiviazione gratuito. Anche il tuo amico riceverà dello spazio extra!',
+        confirm_new_password: "Conferma la nuova Password",
+        contact_us: "Contattaci",
+        contain: 'Contiene',
+        continue: "Continua",
+        copy: 'Copia',
+        copy_link: "Copia il link",
+        copying: "Copia in corso",
+        cover: 'Cover',
+        create_account: "Crea Account",
+        create_free_account: "Crea un account gratis",
+        create_shortcut: "Crea Scorciatoia",
+        current_password: "Password corrente",
+        cut: 'Taglia',
+        date_modified: 'Data ultima modifica',
+        delete: 'Elimina',
+        delete_permanently: "Elimina permanentemente",
+        deploy_as_app: 'Distribuisci come Applicazione',
+        descending: 'Discendente',
+        desktop_background_fit: "Adatta",
+        dir_published_as_website: `%strong% è stato pubblicato su:`,
+        disassociate_dir: "Dissocia la Directory",
+        download: 'Scarica',
+        downloading: "Download in corso",
+        email: "Email",
+        email_or_username: "Email o Nome Utente",
+        empty_trash: 'Svuota Cestino',
+        empty_trash_confirmation: `Sei sicuro di voler svuotare il cestino?`,
+        emptying_trash: 'Il cestino si sta svuotando…',
+        feedback: "Feedback",
+        feedback_c2a: "Usa il form qua sotto per inviarci feedback, commenti, e segnalarci dei bug.",
+        feedback_sent_confirmation: "Grazie per averci contattato. Se hai un indirizzo email associato al tuo account, ti ricontatteremo il prima possibile.",
+        forgot_pass_c2a: "Password dimenticata?",
+        from: "Da",
+        general: "Generale",
+        get_a_copy_of_on_puter: `Ottieni una copia di '%%' su Puter.com!`,
+        get_copy_link: 'Ottieni link di copia',
+        hide_all_windows: "Nascondi tutte le finestre",
+        html_document: 'Documento HTML',
+        image: 'Immagine',
+        invite_link: "Link d’invito",
+        items_in_trash_cannot_be_renamed: `Impossibile rinominare un elemento nel Cestino. Per rinominarlo, è necessario ripristinarlo.`,
+        jpeg_image: 'Immagine JPEG',
+        keep_in_taskbar: 'Blocca nella barra delle applicazioni',
+        log_in: "Accedi",
+        log_out: 'Disconnettiti',
+        move: 'Sposta',
+        moving: "Spostamento in corso",
+        my_websites: "I miei siti web",
+        name: 'Nome',
+        name_cannot_be_empty: 'Il nome non può essere vuoto.',
+        name_cannot_contain_double_period: "Il nome non può contenere '..' .",
+        name_cannot_contain_period: "Il nome non può contenere '.' .",
+        name_cannot_contain_slash: "Il nome non può contenere '/' .",
+        name_must_be_string: "Il nome può contenere una sola linea.",
+        name_too_long: `Il nome non può essere più lungo di %% caratteri.`,
+        new: 'Nuovo',
+        new_folder: 'Nuova Cartella',
+        new_password: "Nuova Password",
+        new_username: "Nuovo Nome Utente",
+        no_dir_associated_with_site: 'Nessuna directory è stata associata all’indirizzo.',
+        no_websites_published: "Non hai pubblicato nessun sito web.",
+        ok: 'OK',
+        open: "Apri",
+        open_in_new_tab: "Apri in una nuova scheda",
+        open_in_new_window: "Apri in una nuova finestra",
+        open_with: "Apri con",
+        password: "Password",
+        password_changed: "Password modificata.",
+        passwords_do_not_match: 'Le caselle `Nuova Password` and `Conferma Nuova Password` non corrispondono.',
+        paste: 'Incolla',
+        paste_into_folder: "Incolla nella cartella",
+        pick_name_for_website: "Scegli un nome per il tuo sito web:",
+        picture: "Immagine",
+        powered_by_puter_js: `Powered by <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "Preparazione in corso...",
+        preparing_for_upload: "Preparazione per l’upload...",
+        properties: "Proprietà",
+        publish: "Pubblica",
+        publish_as_website: 'Pubblica come sito web',
+        recent: "Recenti",
+        recover_password: "Ripristina la Password",
+        refer_friends_c2a: "Ottieni 1 GB di spazio di archiviazione per ogni amico che crea un account e conferma l’email su Puter. Anche il tuo amico riceverà dello spazio extra!",
+        refer_friends_social_media_c2a: `Ottieni 1GB di spazio di spazio di archiviazione gratuito su Puter.com!`,
+        refresh: 'Ricarica',
+        release_address_confirmation: `Sei sicuro di voler liberare questo indirizzo?`,
+        remove_from_taskbar:'Sblocca dalla barra delle applicazioni',
+        rename: 'Rinomina',
+        repeat: 'Ripeti',
+        resend_confirmation_code: "Invia di nuovo il codice di conferma",
+        restore: "Ripristina",
+        save_account_to_get_copy_link: "È necessario creare un account per procedere.",
+        save_account_to_publish: 'È necessario creare un account per procedere.',
+        save_session_c2a: 'Crea un account per salvare la tua sessione e non perdere i tuoi dati.',
+        scan_qr_c2a: 'Scansiona il codice qua sotto per utilizzare questa sessione da altri dispositivi',
+        select: "Seleziona",
+        select_color: 'Seleziona un colore…',
+        send: "Invia",
+        send_password_recovery_email: "Invia Email per il ripristino della password",
+        session_saved: "Grazie per aver creato un account. La sessione è stata salvata",
+        set_new_password: "Imposta una nuova Password",
+        share_to: "Condividi con",
+        show_all_windows: "Mostra tutte le finestre",
+        show_hidden: 'Mostra nascosti',
+        sign_in_with_puter: "Accedi con Puter",
+        sign_up: "Registrati",
+        signing_in: "Accesso in corso…",
+        size: 'Dimensione',
+        sort_by: 'Ordina per',
+        start: 'Start',
+        taking_longer_than_usual: 'Il processo in corso ci sta mettendo più del solito. Attendere prego...',
+        text_document: 'Documento di testo',
+        tos_fineprint: `Cliccando su 'Crea un account gratis' accetti i <a href="https://puter.com/terms" target="_blank">Termini di Servizio</a> e l'<a href="https://puter.com/privacy" target="_blank">Informativa sulla Privacy</a> di Puter.`,
+        trash: 'Cestino',
+        type: 'Tipo',
+        undo: 'Annulla',
+        unzip: "Unzip",
+        upload: 'Carica',
+        upload_here: 'Carica qui',
+        username: "Nome Utente",
+        username_changed: 'Nome utente aggiornato con successo.',
+        versions: "Versioni",
+        yes_release_it: 'Si, rilascialo',
+        you_have_been_referred_to_puter_by_a_friend: "Sei stato invitato su Puter da un amico!",
+        zip: "Zip",
+    }
+}
+
+export default it;

+ 148 - 0
src/i18n/translations/ko.js

@@ -0,0 +1,148 @@
+const ko = {
+    name: "한국어",
+    code: "ko",
+    dictionary: {
+        access_granted_to: "접근 권한 부여",
+        add_existing_account: "기존 계정 추가",
+        all_fields_required: '모든 필드는 필수입니다.',
+        apply: "적용",
+        ascending: '오름차순',
+        background: "배경",
+        browse: "찾아보기",
+        cancel: '취소',
+        center: '중앙',
+        change_desktop_background: '바탕 화면 배경 변경…',
+        change_language: "언어 변경",
+        change_password: "비밀번호 변경",
+        change_username: "사용자 이름 변경",
+        close_all_windows: "모든 창 닫기",
+        color: '색상',
+        confirm_account_for_free_referral_storage_c2a: '계정을 생성하고 이메일 주소를 확인하여 1GB의 무료 저장 공간을 받으십시오. 친구도 1GB의 무료 저장 공간을 받게 됩니다.',
+        confirm_new_password: "새 비밀번호 확인",
+        contact_us: "문의하기",
+        contain: '포함',
+        continue: "계속",
+        copy: '복사',
+        copy_link: "링크 복사",
+        copying: "복사 중",
+        cover: '표지',
+        create_account: "계정 생성",
+        create_free_account: "무료 계정 생성",
+        create_shortcut: "바로 가기 만들기",
+        current_password: "현재 비밀번호",
+        cut: '잘라내기',
+        date_modified: '수정한 날짜',
+        delete: '삭제',
+        delete_permanently: "영구 삭제",
+        deploy_as_app: '앱으로 배포',
+        descending: '내림차순',
+        desktop_background_fit: "맞추기",
+        dir_published_as_website: `%strong% 다음에 게시되었습니다:`,
+        disassociate_dir: "디렉토리 연결 해제",
+        download: '다운로드',
+        downloading: "다운로드 중",
+        email: "이메일",
+        email_or_username: "이메일 또는 사용자 이름",
+        empty_trash: '휴지통 비우기',
+        empty_trash_confirmation: `휴지통의 항목을 영구적으로 삭제하시겠습니까?`,
+        emptying_trash: '휴지통 비우는 중…',
+        feedback: "피드백",
+        feedback_c2a: "아래 양식을 사용하여 피드백, 의견 및 버그 보고를 보내십시오.",
+        feedback_sent_confirmation: "문의해 주셔서 감사합니다. 계정에 이메일이 연결되어 있으면 가능한 빨리 회신 드리겠습니다.",
+        forgot_pass_c2a: "비밀번호를 잊으셨나요?",
+        from: "보낸 사람",
+        general: "일반",
+        get_a_copy_of_on_puter: `Puter.com에서 '%%'의 사본을 받으세요!`,
+        get_copy_link: '링크 복사',
+        hide_all_windows: "모든 창 숨기기",
+        html_document: 'HTML 문서',
+        image: '이미지',
+        invite_link: "초대 링크",
+        items_in_trash_cannot_be_renamed: `이 항목은 휴지통에 있기 때문에 이름을 바꿀 수 없습니다. 이 항목의 이름을 바꾸려면 먼저 휴지통에서 끌어내십시오.`,
+        jpeg_image: 'JPEG 이미지',
+        keep_in_taskbar: '작업 표시줄에 유지',
+        log_in: "로그인",
+        log_out: '로그아웃',
+        move: '이동',
+        moving: "이동 중",
+        my_websites: "내 웹사이트",
+        name: '이름',
+        name_cannot_be_empty: '이름은 비워둘 수 없습니다.',
+        name_cannot_contain_double_period: "이름은 '..' 문자일 수 없습니다.",
+        name_cannot_contain_period: "이름은 '.' 문자일 수 없습니다.",
+        name_cannot_contain_slash: "이름에 '/' 문자를 포함할 수 없습니다.",
+        name_must_be_string: "이름은 문자열만 가능합니다.",
+        name_too_long: `이름은 %%자보다 길 수 없습니다.`,
+        new: '새로운',
+        new_folder: '새 폴더',
+        new_password: "새 비밀번호",
+        new_username: "새 사용자 이름",
+        no_dir_associated_with_site: '이 주소에 연결된 디렉토리가 없습니다.',
+        no_websites_published: "아직 웹사이트를 게시하지 않았습니다.",
+        ok: '확인',
+        open: "열기",
+        open_in_new_tab: "새 탭에서 열기",
+        open_in_new_window: "새 창에서 열기",
+        open_with: "열기 방법",
+        password: "비밀번호",
+        password_changed: "비밀번호가 변경되었습니다.",
+        passwords_do_not_match: '`새 비밀번호`와 `새 비밀번호 확인`이 일치하지 않습니다.',
+        paste: '붙여넣기',
+        paste_into_folder: "폴더에 붙여넣기",
+        pick_name_for_website: "웹사이트 이름을 선택하세요:",
+        picture: "사진",
+        powered_by_puter_js: `Powered by <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "준비 중...",
+        preparing_for_upload: "업로드 준비 중...",
+        properties: "속성",
+        publish: "게시",
+        publish_as_website: '웹사이트로 게시',
+        recent: "최근",
+        recover_password: "비밀번호 찾기",
+        refer_friends_c2a: "Puter에서 계정을 생성하고 확인한 친구마다 1GB를 받으십시오. 친구도 1GB를 받게 됩니다!",
+        refer_friends_social_media_c2a: `Puter.com에서 1GB의 무료 저장 공간을 받으십시오!`,
+        refresh: '새로 고침',
+        release_address_confirmation: `이 주소를 해제하시겠습니까?`,
+        remove_from_taskbar:'작업 표시줄에서 제거',
+        rename: '이름 바꾸기',
+        repeat: '반복',
+        resend_confirmation_code: "확인 코드 다시 보내기",
+        restore: "복원",
+        save_account_to_get_copy_link: "계속하려면 계정을 생성하십시오.",
+        save_account_to_publish: '계속하려면 계정을 생성하십시오.',
+        save_session_c2a: '현재 세션을 저장하고 작업을 잃지 않으려면 계정을 생성하십시오.',
+        scan_qr_c2a: '다른 기기에서 이 세션으로 로그인하려면 아래 코드를 스캔하십시오',
+        select: "선택",
+        select_color: '색상 선택…',
+        send: "보내기",
+        send_password_recovery_email: "비밀번호 복구 이메일 보내기",
+        session_saved: "계정을 생성해 주셔서 감사합니다. 이 세션이 저장되었습니다.",
+        set_new_password: "새 비밀번호 설정",
+        share_to: "공유",
+        show_all_windows: "모든 창 표시",
+        show_hidden: '숨김 항목 표시',
+        sign_in_with_puter: "Puter로 로그인",
+        sign_up: "가입",
+        signing_in: "로그인 중…",
+        size: '크기',
+        sort_by: '정렬 기준',
+        start: '시작',
+        taking_longer_than_usual: '보통보다 조금 더 오래 걸립니다. 잠시만 기다려 주십시오...',
+        text_document: '텍스트 문서',
+        tos_fineprint: `무료 계정 생성을 클릭하면 Puter의 <a href="https://puter.com/terms" target="_blank">서비스 약관</a>과 <a href="https://puter.com/privacy" target="_blank">개인정보 보호정책</a>에 동의하는 것입니다.`,
+        trash: '휴지통',
+        type: '유형',
+        undo: '실행 취소',
+        unzip: "압축 해제",
+        upload: '업로드',
+        upload_here: '여기에 업로드',
+        username: "사용자 이름",
+        username_changed: '사용자 이름이 성공적으로 업데이트되었습니다.',
+        versions: "버전",
+        yes_release_it: '예, 해제합니다',
+        you_have_been_referred_to_puter_by_a_friend: "친구가 Puter로 추천했습니다!",
+        zip: "압축",
+    }
+};
+
+export default ko;

+ 148 - 0
src/i18n/translations/nb.js

@@ -0,0 +1,148 @@
+const nb = {
+    name: "Norsk Bokmål",
+    code: "nb",
+    dictionary: {
+        access_granted_to: "Tilgang gitt til",
+        add_existing_account: "Legg til eksisterende konto",
+        all_fields_required: "Alle felt er obligatoriske.",
+        apply: "Bruk",
+        ascending: "Stigende",
+        background: "Bakgrunn",
+        browse: "Bla gjennom",
+        cancel: "Avbryt",
+        center: "Sentrer",
+        change_desktop_background: "Endre skrivebordsbakgrunn…",
+        change_language: "Endre språk",
+        change_password: "Endre passord",
+        change_username: "Endre brukernavn",
+        close_all_windows: "Lukk alle vinduer",
+        color: "Farge",
+        confirm_account_for_free_referral_storage_c2a: "Opprett en konto og bekreft e-postadressen din for å motta 1 GB gratis lagringsplass. Din venn vil også få 1 GB gratis lagringsplass.",
+        confirm_new_password: "Bekreft nytt passord",
+        contact_us: "Kontakt oss",
+        contain: "Inneholde",
+        continue: "Fortsett",
+        copy: "Kopier",
+        copy_link: "Kopier lenke",
+        copying: "Kopierer",
+        cover: "Dekke",
+        create_account: "Opprett konto",
+        create_free_account: "Opprett gratis konto",
+        create_shortcut: "Opprett snarvei",
+        current_password: "Nåværende passord",
+        cut: "Klipp ut",
+        date_modified: "Endret dato",
+        delete: "Slett",
+        delete_permanently: "Slett permanent",
+        deploy_as_app: "Distribuer som app",
+        descending: "Synkende",
+        desktop_background_fit: "Tilpass",
+        dir_published_as_website: "%strong% er publisert på:",
+        disassociate_dir: "Fjern tilknytning fra mappe",
+        download: "Last ned",
+        downloading: "Laster ned",
+        email: "E-post",
+        email_or_username: "E-post eller brukernavn",
+        empty_trash: "Tøm papirkurv",
+        empty_trash_confirmation: "Er du sikker på at du vil slette alt i papirkurven permanent?",
+        emptying_trash: "Tømmer papirkurv…",
+        feedback: "Tilbakemelding",
+        feedback_c2a: "Vennligst bruk skjemaet nedenfor for å sende oss din tilbakemelding, kommentarer og feilrapporter.",
+        feedback_sent_confirmation: "Takk for at du kontaktet oss. Hvis du har en e-post knyttet til kontoen din, vil du høre fra oss så snart som mulig.",
+        forgot_pass_c2a: "Glemt passord?",
+        from: "Fra",
+        general: "Generelt",
+        get_a_copy_of_on_puter: "Få en kopi av '%%' på Puter.com!",
+        get_copy_link: "Få kopilenke",
+        hide_all_windows: "Skjul alle vinduer",
+        html_document: "HTML-dokument",
+        image: "Bilde",
+        invite_link: "Invitasjonslenke",
+        items_in_trash_cannot_be_renamed: "Dette elementet kan ikke omdøpes fordi det er i papirkurven. For å omdøpe dette elementet, dra det først ut av papirkurven.",
+        jpeg_image: "JPEG-bilde",
+        keep_in_taskbar: "Behold i oppgavelinjen",
+        log_in: "Logg inn",
+        log_out: "Logg ut",
+        move: "Flytt",
+        moving: "Flytter",
+        my_websites: "Mine nettsteder",
+        name: "Navn",
+        name_cannot_be_empty: "Navn kan ikke være tomt.",
+        name_cannot_contain_double_period: "Navn kan ikke inneholde '..'.",
+        name_cannot_contain_period: "Navn kan ikke inneholde '.'-tegnet.",
+        name_cannot_contain_slash: "Navn kan ikke inneholde '/'-tegnet.",
+        name_must_be_string: "Navn kan bare være en streng.",
+        name_too_long: "Navn kan ikke være lengre enn %% tegn.",
+        new: "Ny",
+        new_folder: "Ny mappe",
+        new_password: "Nytt passord",
+        new_username: "Nytt brukernavn",
+        no_dir_associated_with_site: "Ingen mappe er tilknyttet denne adressen.",
+        no_websites_published: "Du har ikke publisert noen nettsteder ennå.",
+        ok: "OK",
+        open: "Åpne",
+        open_in_new_tab: "Åpne i ny fane",
+        open_in_new_window: "Åpne i nytt vindu",
+        open_with: "Åpne med",
+        password: "Passord",
+        password_changed: "Passord endret.",
+        passwords_do_not_match: "`Nytt passord` og `Bekreft nytt passord` stemmer ikke overens.",
+        paste: "Lim inn",
+        paste_into_folder: "Lim inn i mappe",
+        pick_name_for_website: "Velg et navn for nettstedet ditt:",
+        picture: "Bilde",
+        powered_by_puter_js: "Drevet av <a href=\"https://docs.puter.com/\" target=\"_blank\">Puter.js</a>",
+        preparing: "Forbereder...",
+        preparing_for_upload: "Forbereder opplasting...",
+        properties: "Egenskaper",
+        publish: "Publiser",
+        publish_as_website: "Publiser som nettsted",
+        recent: "Nylig",
+        recover_password: "Gjenopprett passord",
+        refer_friends_c2a: "Få 1 GB for hver venn som oppretter og bekrefter en konto på Puter. Vennen din får også 1 GB.",
+        refer_friends_social_media_c2a: "Få 1 GB gratis lagringsplass på Puter.com!",
+        refresh: "Oppdater",
+        release_address_confirmation: "Er du sikker på at du vil frigi denne adressen?",
+        remove_from_taskbar: "Fjern fra oppgavelinjen",
+        rename: "Gi nytt navn",
+        repeat: "Gjenta",
+        resend_confirmation_code: "Send bekreftelseskoden på nytt",
+        restore: "Gjenopprett",
+        save_account_to_get_copy_link: "Vennligst opprett en konto for å fortsette.",
+        save_account_to_publish: "Vennligst opprett en konto for å fortsette.",
+        save_session_c2a: "Opprett en konto for å lagre gjeldende økt og unngå å miste arbeidet ditt.",
+        scan_qr_c2a: "Skann koden nedenfor for å logge inn på denne økten fra andre enheter",
+        select: "Velg",
+        select_color: "Velg farge…",
+        send: "Send",
+        send_password_recovery_email: "Send e-post for gjenoppretting av passord",
+        session_saved: "Takk for at du opprettet en konto. Denne økten er lagret.",
+        set_new_password: "Angi nytt passord",
+        share_to: "Del",
+        show_all_windows: "Vis alle vinduer",
+        show_hidden: "Vis skjulte",
+        sign_in_with_puter: "Logg inn med Puter",
+        sign_up: "Registrer deg",
+        signing_in: "Logger inn…",
+        size: "Størrelse",
+        sort_by: "Sorter etter",
+        start: "Start",
+        taking_longer_than_usual: "Dette tar litt lenger tid enn vanlig. Vennligst vent...",
+        text_document: "Tekstdokument",
+        tos_fineprint: "Ved å klikke på 'Opprett gratis konto' godtar du Puters <a href=\"https://puter.com/terms\" target=\"_blank\">tjenestevilkår</a> og <a href=\"https://puter.com/privacy\" target=\"_blank\">personvernpolicy</a>.",
+        trash: "Papirkurv",
+        type: "Type",
+        undo: "Angre",
+        unzip: "Pakk ut",
+        upload: "Last opp",
+        upload_here: "Last opp her",
+        username: "Brukernavn",
+        username_changed: "Brukernavn oppdatert.",
+        versions: "Versjoner",
+        yes_release_it: "Ja, frigi den",
+        you_have_been_referred_to_puter_by_a_friend: "Du har blitt henvist til Puter av en venn!",
+        zip: "Zip"
+    }
+};
+
+export default nb;

+ 148 - 0
src/i18n/translations/nn.js

@@ -0,0 +1,148 @@
+const nn = {
+    name: "Norsk Nynorsk",
+    code: "nn",
+    dictionary: {
+        access_granted_to: "Tilgang gjeven til",
+        add_existing_account: "Legg til eksisterande konto",
+        all_fields_required: "Alle felt er obligatoriske.",
+        apply: "Bruk",
+        ascending: "Stigande",
+        background: "Bakgrunn",
+        browse: "Bla gjennom",
+        cancel: "Avbryt",
+        center: "Sentrer",
+        change_desktop_background: "Endre skrivebordsbakgrunn…",
+        change_language: "Endre språk",
+        change_password: "Endre passord",
+        change_username: "Endre brukarnamn",
+        close_all_windows: "Lukk alle vindauge",
+        color: "Farge",
+        confirm_account_for_free_referral_storage_c2a: "Opprett ein konto og stadfest e-postadressa di for å få 1 GB gratis lagringsplass. Vennen din vil òg få 1 GB gratis lagringsplass.",
+        confirm_new_password: "Stadfest nytt passord",
+        contact_us: "Kontakt oss",
+        contain: "Inneheld",
+        continue: "Hald fram",
+        copy: "Kopier",
+        copy_link: "Kopier lenkje",
+        copying: "Kopierer",
+        cover: "Dekk",
+        create_account: "Opprett konto",
+        create_free_account: "Opprett gratis konto",
+        create_shortcut: "Opprett snarveg",
+        current_password: "Noeverande passord",
+        cut: "Klipp ut",
+        date_modified: "Endra dato",
+        delete: "Slett",
+        delete_permanently: "Slett permanent",
+        deploy_as_app: "Distribuer som app",
+        descending: "Synkande",
+        desktop_background_fit: "Tilpass",
+        dir_published_as_website: "%strong% er publisert på:",
+        disassociate_dir: "Fjern tilknyting frå mappe",
+        download: "Last ned",
+        downloading: "Lastar ned",
+        email: "E-post",
+        email_or_username: "E-post eller brukarnamn",
+        empty_trash: "Tøm papirkorg",
+        empty_trash_confirmation: "Er du sikker på at du vil slette alt i papirkorga permanent?",
+        emptying_trash: "Tømmer papirkorg…",
+        feedback: "Tilbakemelding",
+        feedback_c2a: "Vennligst bruk skjemaet nedanfor for å sende oss din tilbakemelding, kommentarar og feilrapportar.",
+        feedback_sent_confirmation: "Takk for at du kontakta oss. Om du har ein e-post knytt til kontoen din, vil du høyre frå oss så snart som mogleg.",
+        forgot_pass_c2a: "Gløymt passord?",
+        from: "Frå",
+        general: "Generelt",
+        get_a_copy_of_on_puter: "Få ein kopi av '%%' på Puter.com!",
+        get_copy_link: "Få kopilenkje",
+        hide_all_windows: "Skjul alle vindauge",
+        html_document: "HTML-dokument",
+        image: "Bilete",
+        invite_link: "Invitasjonslenkje",
+        items_in_trash_cannot_be_renamed: "Dette elementet kan ikkje omdøypast fordi det er i papirkorga. For å omdøype dette elementet, dra det først ut av papirkorga.",
+        jpeg_image: "JPEG-bilete",
+        keep_in_taskbar: "Behald i oppgåvelinja",
+        log_in: "Logg inn",
+        log_out: "Logg ut",
+        move: "Flytt",
+        moving: "Flyttar",
+        my_websites: "Mine nettstader",
+        name: "Namn",
+        name_cannot_be_empty: "Namn kan ikkje vere tomt.",
+        name_cannot_contain_double_period: "Namn kan ikkje innehalde '..'.",
+        name_cannot_contain_period: "Namn kan ikkje innehalde '.'-teiknet.",
+        name_cannot_contain_slash: "Namn kan ikkje innehalde '/'-teiknet.",
+        name_must_be_string: "Namn må vere ein streng.",
+        name_too_long: "Namn kan ikkje vere lengre enn %% teikn.",
+        new: "Ny",
+        new_folder: "Ny mappe",
+        new_password: "Nytt passord",
+        new_username: "Nytt brukarnamn",
+        no_dir_associated_with_site: "Ingen mappe er tilknytt denne adressa.",
+        no_websites_published: "Du har ikkje publisert nokre nettstader enno.",
+        ok: "OK",
+        open: "Opne",
+        open_in_new_tab: "Opne i ny fane",
+        open_in_new_window: "Opne i nytt vindauge",
+        open_with: "Opne med",
+        password: "Passord",
+        password_changed: "Passord endra.",
+        passwords_do_not_match: "`Nytt passord` og `Stadfest nytt passord` stemmer ikkje overeins.",
+        paste: "Lim inn",
+        paste_into_folder: "Lim inn i mappe",
+        pick_name_for_website: "Vel eit namn for nettstaden din:",
+        picture: "Bilete",
+        powered_by_puter_js: "Dreve av <a href=\"https://docs.puter.com/\" target=\"_blank\">Puter.js</a>",
+        preparing: "Førebur…",
+        preparing_for_upload: "Førebur opplasting…",
+        properties: "Eigenskapar",
+        publish: "Publiser",
+        publish_as_website: "Publiser som nettstad",
+        recent: "Nyleg",
+        recover_password: "Gjenopprett passord",
+        refer_friends_c2a: "Få 1 GB for kvar ven som opprettar og stadfestar ein konto på Puter. Vennen din får òg 1 GB.",
+        refer_friends_social_media_c2a: "Få 1 GB gratis lagringsplass på Puter.com!",
+        refresh: "Oppdater",
+        release_address_confirmation: "Er du sikker på at du vil sleppe denne adressa?",
+        remove_from_taskbar: "Fjern frå oppgåvelinja",
+        rename: "Gje nytt namn",
+        repeat: "Gjenta",
+        resend_confirmation_code: "Send stadfestingskoden på nytt",
+        restore: "Gjenopprett",
+        save_account_to_get_copy_link: "Vennligst opprett ein konto for å halde fram.",
+        save_account_to_publish: "Vennligst opprett ein konto for å halde fram.",
+        save_session_c2a: "Opprett ein konto for å lagre gjeldande økt og unngå å miste arbeidet ditt.",
+        scan_qr_c2a: "Skann koden nedanfor for å logge inn på denne økta frå andre einingar",
+        select: "Vel",
+        select_color: "Vel farge…",
+        send: "Send",
+        send_password_recovery_email: "Send e-post for gjenoppretting av passord",
+        session_saved: "Takk for at du oppretta ein konto. Denne økta er lagra.",
+        set_new_password: "Set nytt passord",
+        share_to: "Del",
+        show_all_windows: "Vis alle vindauge",
+        show_hidden: "Vis skjulte",
+        sign_in_with_puter: "Logg inn med Puter",
+        sign_up: "Registrer deg",
+        signing_in: "Logger inn…",
+        size: "Storleik",
+        sort_by: "Sorter etter",
+        start: "Start",
+        taking_longer_than_usual: "Dette tar litt lengre tid enn vanleg. Vennligst vent...",
+        text_document: "Tekstdokument",
+        tos_fineprint: "Ved å klikke på 'Opprett gratis konto' godtek du Puters <a href=\"https://puter.com/terms\" target=\"_blank\">tenestevilkår</a> og <a href=\"https://puter.com/privacy\" target=\"_blank\">personvernpolitikk</a>.",
+        trash: "Papirkorg",
+        type: "Type",
+        undo: "Angra",
+        unzip: "Pakk ut",
+        upload: "Last opp",
+        upload_here: "Last opp her",
+        username: "Brukarnamn",
+        username_changed: "Brukarnamn oppdatert.",
+        versions: "Versjonar",
+        yes_release_it: "Ja, slepp den",
+        you_have_been_referred_to_puter_by_a_friend: "Du har blitt referert til Puter av ein ven!",
+        zip: "Zip"
+    }
+};
+
+export default nn;

+ 147 - 0
src/i18n/translations/ro.js

@@ -0,0 +1,147 @@
+const ro = {
+    name: "Română",
+    code: "ro",
+    dictionary: {
+        access_granted_to: "Acces acordat pentru",
+        add_existing_account: "Adaugă cont existent",
+        all_fields_required: 'Toate câmpurile sunt necesare.',
+        apply: "Aplică",
+        ascending: 'Ascendent',
+        background: "Background",
+        browse: "Caută",
+        cancel: 'Anulează',
+        center: 'Center',
+        change_desktop_background: 'Schimbă imaginea de fundal…',
+        change_password: "Schimbă Parola",
+        change_username: "Schimbă Numele",
+        close_all_windows: "Inchide toate ferestrele",
+        color: 'Culoare',
+        confirm_account_for_free_referral_storage_c2a: 'Creați un cont și confirmați adresa de e-mail pentru a primi 1 GB de spațiu de stocare gratuit. Și prietenul tău va primi 1 GB de spațiu de stocare gratuit.',
+        confirm_new_password: "Confirmă Parola Nouă",
+        contact_us: "Contactează-ne",
+        contain: 'Contain',
+        continue: "Continuă",
+        copy: 'Copiază',
+        copy_link: "Copiază link",
+        copying: "Se copiază",
+        cover: 'Cover',
+        create_account: "Crează un cont",
+        create_free_account: "Crează un cont gratuit",
+        create_shortcut: "Crează o scurtătură",
+        current_password: "Parola Curentă",
+        cut: 'Taie',
+        date_modified: 'Dată modificată',
+        delete: 'Șterge',
+        delete_permanently: "Șterge Permanent",
+        deploy_as_app: 'Implementează ca aplicație',
+        descending: 'Descending',
+        desktop_background_fit: "Potrivește fundalul",
+        dir_published_as_website: `%strong% a fost publicat către:`,
+        disassociate_dir: "Dezasociaza folderul",
+        download: 'Descarcă',
+        downloading: "Se descarcă",
+        email: "Mail",
+        email_or_username: "Mail sau Nume de Utilizator",
+        empty_trash: 'Golește Coșul de gunoi',
+        empty_trash_confirmation: `Ești sigur că vrei să ștergi permanent conținutul Coșului de gunoi?`,
+        emptying_trash: 'Coșul de gunoi se golește…',
+        feedback: "Feedback",
+        feedback_c2a: "Vă rugăm să folosiți formularul de mai jos pentru a ne trimite feedback, comentarii și rapoarte de erori.",
+        feedback_sent_confirmation: "Mulțumim că ne-ți contactat. Dacă aveți un e-mail asociat contului dvs, veți primi un răspuns de la noi cât mai curând posibil.",
+        forgot_pass_c2a: "Ai uitat parola?",
+        from: "De la",
+        general: "General",
+        get_a_copy_of_on_puter: `Obțineți o copie a '%%' pe Puter.com!`,
+        get_copy_link: 'Obțineți link-ul copiei',
+        hide_all_windows: "Ascunde toate ferestrele",
+        html_document: 'Document HTML',
+        image: 'Imagine',
+        invite_link: "Link de invitație",
+        items_in_trash_cannot_be_renamed: `Acest articol nu poate fi redenumit deoarece este în coșul de gunoi. Pentru a redenumi acest element, mai întâi scoateți-l din Coșul de gunoi.`,
+        jpeg_image: 'Imagine JPEG',
+        keep_in_taskbar: 'Păstrează în bara de activități',
+        log_in: "Loghează-te",
+        log_out: 'Deconectează-te',
+        move: 'Mută',
+        moving: "Se mută",
+        my_websites: "Site-urile mele",
+        name: 'Nume',
+        name_cannot_be_empty: 'Numele nu poate fi necompletat.',
+        name_cannot_contain_double_period: "Numele nu poate conține ..",
+        name_cannot_contain_period: "Numele nu poate conține .",
+        name_cannot_contain_slash: "Numele nu poate contine /",
+        name_must_be_string: "Numele poate fi doar un șir.",
+        name_too_long: `Numele nu poate fi mai lung de %% caractere.`,
+        new: 'Nou',
+        new_folder: 'Folder nou',
+        new_password: "Parolă nouă",
+        new_username: "Nume de Utilizator nou",
+        no_dir_associated_with_site: 'Niciun director asociat cu această adresă.',
+        no_websites_published: "Nu ați publicat încă niciun site web.",
+        ok: 'OK',
+        open: "Deschide",
+        open_in_new_tab: "Deschide in alt tab",
+        open_in_new_window: "Deschide in fereastră nouă",
+        open_with: "Deschide cu",
+        password: "Parolă",
+        password_changed: "Parolă schimbată.",
+        passwords_do_not_match: '`Parola nouă` și `Confirmă Parola nouă` nu sunt la fel.',
+        paste: 'Inserează',
+        paste_into_folder: "Inserează in folder",
+        pick_name_for_website: "Alegeți un nume pentru site-ul dvs:",
+        picture: "Poza",
+        powered_by_puter_js: `Creat de <a href="https://docs.puter.com/" target="_blank">Puter.js</a>`,
+        preparing: "Preparare...",
+        preparing_for_upload: "Preparare pentru încărcare...",
+        properties: "Proprietăți",
+        publish: "Publică",
+        publish_as_website: 'Publică, ca site web',
+        recent: "Recente",
+        recover_password: "Recuperare Parolă",
+        refer_friends_c2a: "Obțineți 1 GB pentru fiecare prieten care creează și confirmă un cont pe Puter. și prietenul tău va primi 1 GB!",
+        refer_friends_social_media_c2a: `Obțineți 1 GB de spațiu de stocare gratuit pe Puter.com!`,
+        refresh: 'Reîmprospătare',
+        release_address_confirmation: `Sigur doriți să eliberați această adresă?`,
+        remove_from_taskbar:'Eliminați din bara de activități',
+        rename: 'Redenumește',
+        repeat: 'Repetă',
+        resend_confirmation_code: "Re-trimite cod de confirmare",
+        restore: "Restaurare",
+        save_account_to_get_copy_link: "Vă rugăm să creați un cont pentru a copia un link.",
+        save_account_to_publish: 'Vă rugăm să creați un cont pentru a publica.',
+        save_session_c2a: 'Creați un cont pentru a vă salva sesiunea curentă și pentru a evita pierderea muncii.',
+        scan_qr_c2a: 'Scanați codul de mai jos pentru a vă conecta la această sesiune de pe alte dispozitive',
+        select: "Selectează",
+        select_color: 'Selectează culoare…',
+        send: "Trimite",
+        send_password_recovery_email: "Trimite mail de recuperare parolă",
+        session_saved: "Vă mulțumim pentru crearea unui cont. Această sesiune a fost salvată.",
+        set_new_password: "Setează o parolă Nouă",
+        share_to: "Distribuie către",
+        show_all_windows: "Afișați toate ferestrele",
+        show_hidden: 'Arată ascuns',
+        sign_in_with_puter: "Conectați-vă cu Puter",
+        sign_up: "Inscrie-te",
+        signing_in: "Se conectează…",
+        size: 'Mărime',
+        sort_by: 'Sortează dupa',
+        start: 'Start',
+        taking_longer_than_usual: 'Durează puțin mai mult decât de obicei. Vă rugăm așteptați...',
+        text_document: 'Document Text',
+        tos_fineprint: `Făcând clic pe „Creați un cont gratuit”, sunteți de acord cu <a href="https://puter.com/terms" target="_blank">Termenii si conditiile</a> si <a href="https://puter.com/privacy" target="_blank">Politia de Confidentialitate Puter.com</a>.`,
+        trash: 'Coș de gunoi',
+        type: 'Type',
+        undo: 'Undo',
+        unzip: "Unzip",
+        upload: 'Incarcă',
+        upload_here: 'Incarcă aici',
+        username: "Nume de Utilizator",
+        username_changed: 'Nume de Utilizator actualizat cu succes.',
+        versions: "Versiuni",
+        yes_release_it: 'Da, eliberează-l',
+        you_have_been_referred_to_puter_by_a_friend: "Ai fost invitat pe Puter de către un prieten!",
+        zip: "Zip",
+    }
+}
+
+export default ro;

+ 148 - 0
src/i18n/translations/sv.js

@@ -0,0 +1,148 @@
+const sv = {
+    name: "Svenska",
+    code: "sv",
+    dictionary: {
+        access_granted_to: "Tillgång beviljad till",
+        add_existing_account: "Lägg till befintligt konto",
+        all_fields_required: "Alla fält är obligatoriska.",
+        apply: "Tillämpa",
+        ascending: "Stigande",
+        background: "Bakgrund",
+        browse: "Bläddra",
+        cancel: "Avbryt",
+        center: "Centrera",
+        change_desktop_background: "Ändra skrivbordsbakgrund…",
+        change_language: "Ändra språk",
+        change_password: "Byt lösenord",
+        change_username: "Byt användarnamn",
+        close_all_windows: "Stäng alla fönster",
+        color: "Färg",
+        confirm_account_for_free_referral_storage_c2a: "Skapa ett konto och bekräfta din e-postadress för att få 1 GB gratis lagringsutrymme. Din vän får också 1 GB gratis lagringsutrymme.",
+        confirm_new_password: "Bekräfta nytt lösenord",
+        contact_us: "Kontakta oss",
+        contain: "Innehålla",
+        continue: "Fortsätt",
+        copy: "Kopiera",
+        copy_link: "Kopiera länk",
+        copying: "Kopierar",
+        cover: "Täcka",
+        create_account: "Skapa konto",
+        create_free_account: "Skapa gratis konto",
+        create_shortcut: "Skapa genväg",
+        current_password: "Nuvarande lösenord",
+        cut: "Klipp ut",
+        date_modified: "Ändringsdatum",
+        delete: "Radera",
+        delete_permanently: "Radera permanent",
+        deploy_as_app: "Distribuera som app",
+        descending: "Fallande",
+        desktop_background_fit: "Anpassa",
+        dir_published_as_website: "%strong% är publicerat på:",
+        disassociate_dir: "Avassociera mapp",
+        download: "Ladda ner",
+        downloading: "Laddar ner",
+        email: "E-post",
+        email_or_username: "E-post eller användarnamn",
+        empty_trash: "Töm papperskorgen",
+        empty_trash_confirmation: "Är du säker på att du vill permanent radera allt i papperskorgen?",
+        emptying_trash: "Tömmer papperskorgen…",
+        feedback: "Feedback",
+        feedback_c2a: "Vänligen använd formuläret nedan för att skicka oss din feedback, kommentarer och felrapporter.",
+        feedback_sent_confirmation: "Tack för att du kontaktade oss. Om du har en e-post kopplad till ditt konto kommer du att höra från oss så snart som möjligt.",
+        forgot_pass_c2a: "Glömt lösenord?",
+        from: "Från",
+        general: "Allmänt",
+        get_a_copy_of_on_puter: "Få en kopia av '%%' på Puter.com!",
+        get_copy_link: "Få kopieringslänk",
+        hide_all_windows: "Dölj alla fönster",
+        html_document: "HTML-dokument",
+        image: "Bild",
+        invite_link: "Inbjudningslänk",
+        items_in_trash_cannot_be_renamed: "Det här objektet kan inte byta namn eftersom det är i papperskorgen. För att byta namn på detta objekt, dra det först ur papperskorgen.",
+        jpeg_image: "JPEG-bild",
+        keep_in_taskbar: "Behåll i aktivitetsfältet",
+        log_in: "Logga in",
+        log_out: "Logga ut",
+        move: "Flytta",
+        moving: "Flyttar",
+        my_websites: "Mina webbplatser",
+        name: "Namn",
+        name_cannot_be_empty: "Namn kan inte vara tomt.",
+        name_cannot_contain_double_period: "Namn kan inte innehålla '..'.",
+        name_cannot_contain_period: "Namn kan inte innehålla '.'-tecknet.",
+        name_cannot_contain_slash: "Namn kan inte innehålla '/'-tecknet.",
+        name_must_be_string: "Namn måste vara en sträng.",
+        name_too_long: "Namn kan inte vara längre än %% tecken.",
+        new: "Ny",
+        new_folder: "Ny mapp",
+        new_password: "Nytt lösenord",
+        new_username: "Nytt användarnamn",
+        no_dir_associated_with_site: "Ingen mapp är associerad med denna adress.",
+        no_websites_published: "Du har inte publicerat några webbplatser än.",
+        ok: "OK",
+        open: "Öppna",
+        open_in_new_tab: "Öppna i ny flik",
+        open_in_new_window: "Öppna i nytt fönster",
+        open_with: "Öppna med",
+        password: "Lösenord",
+        password_changed: "Lösenord ändrat.",
+        passwords_do_not_match: "`Nytt lösenord` och `Bekräfta nytt lösenord` stämmer inte överens.",
+        paste: "Klistra in",
+        paste_into_folder: "Klistra in i mapp",
+        pick_name_for_website: "Välj ett namn för din webbplats:",
+        picture: "Bild",
+        powered_by_puter_js: "Drivs av <a href=\"https://docs.puter.com/\" target=\"_blank\">Puter.js</a>",
+        preparing: "Förbereder...",
+        preparing_for_upload: "Förbereder för uppladdning...",
+        properties: "Egenskaper",
+        publish: "Publicera",
+        publish_as_website: "Publicera som webbplats",
+        recent: "Senaste",
+        recover_password: "Återställ lösenord",
+        refer_friends_c2a: "Få 1 GB för varje vän som skapar och bekräftar ett konto på Puter. Din vän får också 1 GB.",
+        refer_friends_social_media_c2a: "Få 1 GB gratis lagringsutrymme på Puter.com!",
+        refresh: "Uppdatera",
+        release_address_confirmation: "Är du säker på att du vill frigöra denna adress?",
+        remove_from_taskbar: "Ta bort från aktivitetsfältet",
+        rename: "Byt namn",
+        repeat: "Upprepa",
+        resend_confirmation_code: "Skicka bekräftelsekoden igen",
+        restore: "Återställ",
+        save_account_to_get_copy_link: "Vänligen skapa ett konto för att fortsätta.",
+        save_account_to_publish: "Vänligen skapa ett konto för att fortsätta.",
+        save_session_c2a: "Skapa ett konto för att spara den nuvarande sessionen och undvika att förlora ditt arbete.",
+        scan_qr_c2a: "Skanna koden nedan för att logga in på denna session från andra enheter",
+        select: "Välj",
+        select_color: "Välj färg…",
+        send: "Skicka",
+        send_password_recovery_email: "Skicka e-post för återställning av lösenord",
+        session_saved: "Tack för att du skapade ett konto. Denna session är sparad.",
+        set_new_password: "Ange nytt lösenord",
+        share_to: "Dela till",
+        show_all_windows: "Visa alla fönster",
+        show_hidden: "Visa dolda",
+        sign_in_with_puter: "Logga in med Puter",
+        sign_up: "Registrera dig",
+        signing_in: "Loggar in…",
+        size: "Storlek",
+        sort_by: "Sortera efter",
+        start: "Start",
+        taking_longer_than_usual: "Detta tar längre tid än vanligt. Vänligen vänta...",
+        text_document: "Textdokument",
+        tos_fineprint: "Genom att klicka på 'Skapa gratis konto' godkänner du Puters <a href=\"https://puter.com/terms\" target=\"_blank\">användarvillkor</a> och <a href=\"https://puter.com/privacy\" target=\"_blank\">integritetspolicy</a>.",
+        trash: "Papperskorg",
+        type: "Typ",
+        undo: "Ångra",
+        unzip: "Packa upp",
+        upload: "Ladda upp",
+        upload_here: "Ladda upp här",
+        username: "Användarnamn",
+        username_changed: "Användarnamn uppdaterat.",
+        versions: "Versioner",
+        yes_release_it: "Ja, frigör den",
+        you_have_been_referred_to_puter_by_a_friend: "Du har blivit hänvisad till Puter av en vän!",
+        zip: "Zip"
+    }
+};
+
+export default sv;

+ 31 - 0
src/i18n/translations/translations.js

@@ -0,0 +1,31 @@
+import bn from './bn.js'
+import da from './da.js';
+import de from './de.js'
+import en from './en.js';
+import fa from './fa.js';
+import fi from './fi.js';
+import fr from './fr.js';
+import it from './it.js';
+import ko from './ko.js';
+import nb from './nb.js';
+import nn from './nn.js';
+import ro from './ro.js';
+import sv from './sv.js';
+import zh from './zh.js';
+
+export default {
+    bn,
+    da,
+    de,
+    en,
+    fa,
+    fi,
+    fr,
+    it,
+    ko,
+    nb,
+    nn,
+    ro,
+    sv,
+    zh,
+};

+ 148 - 0
src/i18n/translations/zh.js

@@ -0,0 +1,148 @@
+const zh = {
+    name: "中文",
+    code: "zh",
+    dictionary: {
+        access_granted_to: "访问授权给",
+        add_existing_account: "添加现有帐户",
+        all_fields_required: '所有字段都是必需的。',
+        apply: "应用",
+        ascending: '升序',
+        background: "背景",
+        browse: "浏览",
+        cancel: '取消',
+        center: '中心',
+        change_desktop_background: '更改桌面背景…',
+        change_language: "更改语言",
+        change_password: "更改密码",
+        change_username: "更改用户名",
+        close_all_windows: "关闭所有窗口",
+        color: '颜色',
+        confirm_account_for_free_referral_storage_c2a: '创建帐户并确认您的电子邮件地址,以获得1 GB的免费存储空间。您的朋友也将获得1 GB的免费存储空间。',
+        confirm_new_password: "确认新密码",
+        contact_us: "联系我们",
+        contain: '包含',
+        continue: "继续",
+        copy: '复制',
+        copy_link: "复制链接",
+        copying: "复制",
+        cover: '封面',
+        create_account: "创建帐户",
+        create_free_account: "创建免费帐户",
+        create_shortcut: "创建快捷方式",
+        current_password: "当前密码",
+        cut: '剪切',
+        date_modified: '修改日期',
+        delete: '删除',
+        delete_permanently: "永久删除",
+        deploy_as_app: '部署为应用',
+        descending: '降序',
+        desktop_background_fit: "适合",
+        dir_published_as_website: `%strong% 已发布到:`,
+        disassociate_dir: "取消关联目录",
+        download: '下载',
+        downloading: "下载",
+        email: "电子邮件",
+        email_or_username: "电子邮件或用户名",
+        empty_trash: '清空回收站',
+        empty_trash_confirmation: `您确定要永久删除回收站中的项目吗?`,
+        emptying_trash: '清空回收站…',
+        feedback: "反馈",
+        feedback_c2a: "请使用下面的表格向我们发送您的反馈、评论和错误报告。",
+        feedback_sent_confirmation: "感谢您与我们联系。如果您的帐户关联有电子邮件,我们会尽快回复您。",
+        forgot_pass_c2a: "忘记密码?",
+        from: "从",
+        general: "一般",
+        get_a_copy_of_on_puter: `在 Puter.com 上获取 '%%' 的副本!`,
+        get_copy_link: '获取复制链接',
+        hide_all_windows: "隐藏所有窗口",
+        html_document: 'HTML 文档',
+        image: '图像',
+        invite_link: "邀请链接",
+        items_in_trash_cannot_be_renamed: `此项目无法重命名,因为它在回收站中。要重命名此项目,请先将其拖出回收站。`,
+        jpeg_image: 'JPEG 图像',
+        keep_in_taskbar: '保持在任务栏',
+        log_in: "登录",
+        log_out: '登出',
+        move: '移动',
+        moving: "移动",
+        my_websites: "我的网站",
+        name: '名称',
+        name_cannot_be_empty: '名称不能为空。',
+        name_cannot_contain_double_period: "名称不能是'..'字符。",
+        name_cannot_contain_period: "名称不能是'.'字符。",
+        name_cannot_contain_slash: "名称不能包含'/'字符。",
+        name_must_be_string: "名称只能是字符串。",
+        name_too_long: `名称不能超过 %% 个字符。`,
+        new: '新',
+        new_folder: '新文件夹',
+        new_password: "新密码",
+        new_username: "新用户名",
+        no_dir_associated_with_site: '此地址没有关联的目录。',
+        no_websites_published: "您尚未发布任何网站。",
+        ok: '好的',
+        open: "打开",
+        open_in_new_tab: "在新标签页中打开",
+        open_in_new_window: "在新窗口中打开",
+        open_with: "打开方式",
+        password: "密码",
+        password_changed: "密码已更改。",
+        passwords_do_not_match: '`新密码` 和 `确认新密码` 不匹配。',
+        paste: '粘贴',
+        paste_into_folder: "粘贴到文件夹",
+        pick_name_for_website: "为您的网站选择一个名称:",
+        picture: "图片",
+        powered_by_puter_js: `由 <a href="https://docs.puter.com/" target="_blank">Puter.js</a> 提供支持`,
+        preparing: "准备中...",
+        preparing_for_upload: "准备上传...",
+        properties: "属性",
+        publish: "发布",
+        publish_as_website: '发布为网站',
+        recent: "最近",
+        recover_password: "找回密码",
+        refer_friends_c2a: "每个创建并确认 Puter 帐户的朋友都会为您获得 1 GB。您的朋友也将获得 1 GB!",
+        refer_friends_social_media_c2a: `在 Puter.com 上获取 1 GB 的免费存储空间!`,
+        refresh: '刷新',
+        release_address_confirmation: `您确定要释放此地址吗?`,
+        remove_from_taskbar:'从任务栏中删除',
+        rename: '重命名',
+        repeat: '重复',
+        resend_confirmation_code: "重新发送确认码",
+        restore: "还原",
+        save_account_to_get_copy_link: "请创建帐户以继续。",
+        save_account_to_publish: '请创建帐户以继续。',
+        save_session_c2a: '创建帐户以保存当前会话,避免丢失工作。',
+        scan_qr_c2a: '扫描下面的代码以从其他设备登录此会话',
+        select: "选择",
+        select_color: '选择颜色…',
+        send: "发送",
+        send_password_recovery_email: "发送密码恢复电子邮件",
+        session_saved: "感谢您创建帐户。此会话已保存。",
+        set_new_password: "设置新密码",
+        share_to: "分享到",
+        show_all_windows: "显示所有窗口",
+        show_hidden: '显示隐藏',
+        sign_in_with_puter: "使用 Puter 登录",
+        sign_up: "注册",
+        signing_in: "登录中…",
+        size: '大小',
+        sort_by: '排序方式',
+        start: '开始',
+        taking_longer_than_usual: '需要的时间比平时长一点。请稍等...',
+        text_document: '文本文档',
+        tos_fineprint: `点击“创建免费帐户”即表示您同意 Puter 的 <a href="https://puter.com/terms" target="_blank">服务条款</a> 和 <a href="https://puter.com/privacy" target="_blank">隐私政策</a>。`,
+        trash: '回收站',
+        type: '类型',
+        undo: '撤销',
+        unzip: "解压缩",
+        upload: '上传',
+        upload_here: '在此上传',
+        username: "用户名",
+        username_changed: '用户名已成功更新。',
+        versions: "版本",
+        yes_release_it: '是的,释放它',
+        you_have_been_referred_to_puter_by_a_friend: "您已经被朋友推荐到 Puter!",
+        zip: "压缩",
+    }
+};
+
+export default zh;

+ 5 - 0
src/initgui.js

@@ -46,6 +46,9 @@ window.initgui = async function(){
     if(window.api_origin && puter.APIOrigin !== window.api_origin)
         puter.setAPIOrigin(api_origin);
 
+    // determine locale
+    window.locale = window.user_preferences.language;
+
     // Checks the type of device the user is on (phone, tablet, or desktop).
     // Depending on the device type, it sets a class attribute on the body tag 
     // to style or script the page differently for each device type.
@@ -326,6 +329,7 @@ window.initgui = async function(){
             // Load desktop, only if we're not embedded in a popup
             // -------------------------------------------------------------------------------------
             if(!window.embedded_in_popup){
+                await get_auto_arrange_data()
                 puter.fs.stat(desktop_path, async function(desktop_fsentry){
                     UIDesktop({desktop_fsentry: desktop_fsentry});
                 })
@@ -677,6 +681,7 @@ window.initgui = async function(){
         // Load desktop, if not embedded in a popup
         // -------------------------------------------------------------------------------------
         if(!window.embedded_in_popup){
+            await get_auto_arrange_data();
             puter.fs.stat(desktop_path, function (desktop_fsentry) {
                 UIDesktop({ desktop_fsentry: desktop_fsentry });
             })

+ 1 - 0
src/static-assets.js

@@ -48,6 +48,7 @@ const js_paths = [
     '/helpers.js',
     '/IPC.js',
     '/globals.js',
+    `/i18n/i18n.js`,
 ]
 
 module.exports = { lib_paths, css_paths, js_paths }

部分文件因为文件数量过多而无法显示