Przeglądaj źródła

Redesign interface selector and add startup setting

Rebuild the post-login interface selector with a card layout, dark mode support, localization and the ArozOS logo. The remembered choice is validated against the user's available interfaces, and the selector can be forced open with ?switch.

Add a Startup Interface page in Desktop settings to pick or clear the remembered workspace, or switch now.

Hide Interface Module entries (Desktop, Dashboard) from the desktop, mobile and Dashboard app launchers.

System Settings cards now show localized descriptions (desc/<group>/<name> keys), with translations added for all supported languages. Management Gateway's Switch Services link now opens the selector with ?switch.

Fix typos in two setting descriptions.
Toby Chui 1 dzień temu
rodzic
commit
4eca386814

+ 1 - 0
src/desktop.go

@@ -62,6 +62,7 @@ func DesktopInit() {
 		{Name: "Sounds", Desc: "System Sound Settings", StartDir: "SystemAO/desktop/settings/sounds.html"},
 		{Name: "Theme", Desc: "System Theme Color", StartDir: "SystemAO/desktop/settings/theme.html"},
 		{Name: "Mobile UX", Desc: "Mobile Desktop Shortcuts", StartDir: "SystemAO/desktop/settings/mobile_ux.html"},
+		{Name: "Startup Interface", Desc: "Workspace opened after sign in", StartDir: "SystemAO/desktop/settings/interface.html"},
 	} {
 		setting.IconPath = "SystemAO/desktop/img/personalization.png"
 		setting.Group = "Desktop"

+ 1 - 1
src/startup.flags.go

@@ -172,7 +172,7 @@ func StartupFlagsInit() {
 	//Register a boot flag modifier
 	registerSetting(settingModule{
 		Name:         "Runtime",
-		Desc:         "Change startup paramter in runtime",
+		Desc:         "Change startup parameters at runtime",
 		IconPath:     "SystemAO/info/img/runtime.png",
 		Group:        "Info",
 		StartDir:     "SystemAO/boot/bootflags.html",

+ 2 - 0
src/web/Dashboard/index.html

@@ -1401,6 +1401,8 @@ function loadModules() {
     ao_module_agirun("Dashboard/backend/getModules.agi", {}, function(data) {
         data = parseJSON(data);
         allModules = Array.isArray(data) ? data : [];
+        //Interface Modules (Desktop, this Dashboard, ...) are what the user boots into, not apps to launch
+        allModules = allModules.filter(function(mod) { return mod.Group !== "Interface Module"; });
         renderPinnedApps();
         renderAppGrid("all");
     }, function() {

+ 1 - 1
src/web/Management Gateway/index.html

@@ -27,7 +27,7 @@
                 <span style="font-weight: bold; font-size: 150%; margin-right: 12px; margin-top:-16px;">arozos</span><span style="margin-top:18px; margin-left: -60px; font-size: 80%;">Management Gateway</span> 
             </div>
             <div class="right menu">
-                <a class="item nondesktop" href="../SystemAO/boot/interface_selector.html">
+                <a class="item nondesktop" href="../SystemAO/boot/interface_selector.html?switch">
                     <i class="exchange icon"></i> Switch Services
                  </a>
                 <a class="item nondesktop" onclick="logout();">

+ 478 - 84
src/web/SystemAO/boot/interface_selector.html

@@ -1,107 +1,501 @@
 <!DOCTYPE html>
 <html>
     <head>
-        <title>Interface Selector</title>
+        <title>Choose your workspace</title>
         <meta charset="UTF-8">
-        <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
-        <link rel="stylesheet" href="../../script/semantic/semantic.css">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+        <meta name="theme-color" content="#f7f9fc">
+        <link rel="icon" type="image/png" href="../../img/system/favicon.png">
+        <link rel="stylesheet" href="../../script/semantic/semantic.min.css">
         <script type="application/javascript" src="../../script/jquery.min.js"></script>
-        <script type="application/javascript" src="../../script/semantic/semantic.js"></script>
-       <style>
-           .interfaceModule{
-               cursor: pointer;
-               border: 2px solid transparent !important;
-               height: 120px;
-           }
-           .interfaceModule:hover{
-                border: 2px solid #407ded !important;
-                background-color: #d1e1ff;
-           }
-           a{
-               cursor: pointer;
-           }
+        <script type="application/javascript" src="../../script/ao_module.js"></script>
+        <script type="application/javascript" src="../../script/applocale.js"></script>
+        <style>
+            :root{
+                --is-bg: #f7f9fc;
+                --is-surface: #ffffff;
+                --is-text: #0f172a;
+                --is-dim: #64748b;
+                --is-muted: #94a3b8;
+                --is-border: #e5e9f0;
+                --is-accent: #2f6fed;
+                --is-accent-soft: #eef4ff;
+                --is-accent-border: #4a83f0;
+                --is-chip: #f1f4f8;
+                --is-tile: #f4f7fb;
+                --is-shadow: 0 1px 2px rgba(15,23,42,0.04), 0 4px 12px rgba(15,23,42,0.04);
+            }
+            @media (prefers-color-scheme: dark){
+                :root{
+                    --is-bg: #0f141c;
+                    --is-surface: #171e29;
+                    --is-text: #e8edf5;
+                    --is-dim: #a3afc2;
+                    --is-muted: #6f7c91;
+                    --is-border: #262f3d;
+                    --is-accent: #5b8ff5;
+                    --is-accent-soft: #1a2740;
+                    --is-accent-border: #4a7be0;
+                    --is-chip: #212a37;
+                    --is-tile: #1f2734;
+                    --is-shadow: 0 1px 2px rgba(0,0,0,0.3), 0 4px 12px rgba(0,0,0,0.2);
+                }
+            }
+            *{ box-sizing: border-box; }
+            html, body{
+                margin: 0;
+                padding: 0;
+                background: var(--is-bg);
+                color: var(--is-text);
+                font-family: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, "Noto Sans TC", "Microsoft JhengHei", sans-serif;
+                font-size: 14px;
+                -webkit-font-smoothing: antialiased;
+            }
+            body{
+                display: flex;
+                flex-direction: column;
+                min-height: 100vh;
+                min-height: 100dvh;
+            }
+            .is-bar{
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+                gap: 12px;
+                width: 100%;
+                max-width: 760px;
+                margin: 0 auto;
+                padding: 12px 24px;
+            }
+            .is-top-wrap{ border-bottom: 1px solid var(--is-border); }
+            .is-bottom-wrap{ border-top: 1px solid var(--is-border); }
+            .is-brand{
+                display: flex;
+                align-items: center;
+                gap: 12px;
+                min-width: 0;
+                font-size: 15px;
+                font-weight: 600;
+            }
+            .is-brand picture{ display: flex; }
+            .is-logo{
+                display: block;
+                height: 26px;
+                width: auto;
+                max-width: 120px;
+                object-fit: contain;
+                object-position: left center;
+                padding: 0.1em;
+            }
+            .is-brand-sep{
+                width: 1px;
+                height: 18px;
+                background: var(--is-border);
+            }
+            .is-brand .hostname{
+                overflow: hidden;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+            }
+            .is-main{
+                flex: 1;
+                width: 100%;
+                max-width: 760px;
+                margin: 0 auto;
+                padding: 40px 24px 28px;
+            }
+            .is-title{
+                font-size: 26px;
+                line-height: 1.2;
+                font-weight: 700;
+                letter-spacing: -0.01em;
+                margin: 0 0 6px;
+            }
+            .is-subtitle{
+                font-size: 14px;
+                color: var(--is-dim);
+                margin: 0 0 22px;
+            }
+            .is-list{
+                display: flex;
+                flex-direction: column;
+                gap: 12px;
+            }
+            .is-card{
+                display: flex;
+                align-items: center;
+                gap: 18px;
+                width: 100%;
+                padding: 14px 16px 14px 14px;
+                background: var(--is-surface);
+                border: 1.5px solid var(--is-border);
+                border-radius: 12px;
+                box-shadow: var(--is-shadow);
+                cursor: pointer;
+                text-align: left;
+                color: inherit;
+                font: inherit;
+                transition: border-color 0.15s, background-color 0.15s, transform 0.15s;
+            }
+            .is-card:hover, .is-card:focus-visible, .is-card.highlight{
+                border-color: var(--is-accent-border);
+                background: linear-gradient(90deg, var(--is-accent-soft) 0%, var(--is-surface) 100%);
+                outline: none;
+            }
+            .is-card:active{ transform: scale(0.995); }
+            .is-tile{
+                flex-shrink: 0;
+                width: 64px;
+                height: 64px;
+                border-radius: 12px;
+                background: var(--is-tile);
+                display: flex;
+                align-items: center;
+                justify-content: center;
+            }
+            .is-tile img{
+                width: 46px;
+                height: 46px;
+                object-fit: contain;
+            }
+            .is-body{
+                flex: 1;
+                min-width: 0;
+            }
+            .is-name{
+                font-size: 17px;
+                font-weight: 700;
+                margin: 0 0 2px;
+            }
+            .is-desc{
+                font-size: 13px;
+                color: var(--is-dim);
+                margin: 0 0 8px;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                display: -webkit-box;
+                -webkit-line-clamp: 2;
+                -webkit-box-orient: vertical;
+            }
+            .is-chip{
+                display: inline-flex;
+                align-items: center;
+                gap: 5px;
+                padding: 3px 10px;
+                border-radius: 999px;
+                background: var(--is-chip);
+                color: var(--is-dim);
+                font-size: 12px;
+                font-weight: 500;
+            }
+            .is-chip i.icon{
+                margin: 0;
+                height: auto;
+                font-size: 12px;
+            }
+            .is-chip.desktop{
+                background: var(--is-accent-soft);
+                color: var(--is-accent);
+            }
+            .is-card:hover .is-chip.desktop, .is-card.highlight .is-chip.desktop{
+                background: rgba(47,111,237,0.12);
+            }
+            .is-go{
+                flex-shrink: 0;
+                width: 36px;
+                height: 36px;
+                border-radius: 50%;
+                border: 1.5px solid var(--is-border);
+                background: var(--is-surface);
+                color: var(--is-dim);
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                transition: color 0.15s;
+            }
+            .is-card:hover .is-go, .is-card.highlight .is-go{ color: var(--is-accent); }
+            .is-options{ margin-top: 22px; }
+            .is-remember{
+                display: inline-flex;
+                align-items: center;
+                gap: 10px;
+                font-size: 14px;
+                cursor: pointer;
+                user-select: none;
+            }
+            .is-remember input{
+                width: 17px;
+                height: 17px;
+                margin: 0;
+                accent-color: var(--is-accent);
+                cursor: pointer;
+            }
+            .is-hint{
+                display: flex;
+                align-items: center;
+                gap: 10px;
+                margin-top: 8px;
+                font-size: 12.5px;
+                color: var(--is-dim);
+            }
+            .is-hint svg{
+                flex-shrink: 0;
+                color: var(--is-muted);
+            }
+            .is-empty{
+                padding: 28px;
+                border: 1.5px dashed var(--is-border);
+                border-radius: 12px;
+                color: var(--is-dim);
+                text-align: center;
+            }
+            .is-bottom{
+                font-size: 13px;
+                color: var(--is-dim);
+            }
+            .is-user{
+                display: flex;
+                align-items: center;
+                gap: 8px;
+                min-width: 0;
+            }
+            .is-user i.icon, .is-logout i.icon{
+                margin: 0;
+                width: auto;
+                height: auto;
+                line-height: 1;
+            }
+            .is-user > span{
+                overflow: hidden;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+            }
+            .is-user b{
+                color: var(--is-accent);
+                font-weight: 500;
+            }
+            .is-logout{
+                flex-shrink: 0;
+                display: inline-flex;
+                align-items: center;
+                gap: 6px;
+                border: none;
+                background: none;
+                padding: 6px 4px;
+                color: var(--is-accent);
+                font: inherit;
+                cursor: pointer;
+            }
+            .is-logout:hover{ text-decoration: underline; }
+
+            @media (max-width: 600px){
+                .is-bar{ padding: 10px 16px; }
+                .is-logo{ height: 22px; max-width: 100px; }
+                .is-main{ padding: 24px 16px 20px; }
+                .is-title{ font-size: 22px; }
+                .is-subtitle{ font-size: 13px; margin-bottom: 16px; }
+                .is-list{ gap: 10px; }
+                .is-card{ gap: 12px; padding: 12px; }
+                .is-tile{ width: 52px; height: 52px; border-radius: 10px; }
+                .is-tile img{ width: 38px; height: 38px; }
+                .is-name{ font-size: 16px; }
+                .is-desc{ font-size: 12.5px; margin-bottom: 6px; }
+                .is-go{ width: 30px; height: 30px; }
+                .is-go svg{ width: 16px; height: 16px; }
+                .is-options{ margin-top: 18px; }
+            }
+            @media (max-width: 360px){
+                .is-go{ display: none; }
+                .is-brand-sep, .is-brand .hostname{ display: none; }
+            }
         </style>
     </head>
     <body>
-        <br><br>
-        <div class="ui text container">
-            <h2>Please choose a service to start</h2>
-            <div class="ui divider"></div>
-            <div id="serviceList" class="ui segment">
-                
-            </div>
-            <div id="remember" class="ui checkbox">
-                <input type="checkbox" name="remember">
-                <label>Remember option on this browser</label>
+        <div class="is-top-wrap">
+            <header class="is-bar">
+                <div class="is-brand">
+                    <picture>
+                        <source srcset="../../img/system/auth_icon_white.png" media="(prefers-color-scheme: dark)">
+                        <img class="is-logo" src="../../img/system/auth_icon_black.png" alt="">
+                    </picture>
+                    <span class="is-brand-sep"></span>
+                    <span class="hostname">ArozOS</span>
+                </div>
+            </header>
+        </div>
+
+        <main class="is-main">
+            <h1 class="is-title" locale="selector/title">Choose your workspace</h1>
+            <p class="is-subtitle" locale="selector/subtitle">Select a service to continue</p>
+
+            <div id="serviceList" class="is-list"></div>
+
+            <div class="is-options">
+                <label class="is-remember">
+                    <input type="checkbox" id="remember">
+                    <span locale="selector/remember">Remember my choice on this browser</span>
+                </label>
+                <div class="is-hint">
+                    <svg width="17" height="17" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="1.6"/><path d="M12 11v5.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><circle cx="12" cy="7.8" r="1.1" fill="currentColor"/></svg>
+                    <span locale="selector/hint">You can change this setting later in System Settings.</span>
+                </div>
             </div>
+        </main>
 
-            <div class="ui divider"></div>
-            <p>or <a onclick="logout();">Logout</a></p>
+        <div class="is-bottom-wrap">
+            <footer class="is-bar is-bottom">
+                <div class="is-user">
+                    <i class="user outline icon"></i>
+                    <span><span locale="selector/signedin">Signed in as</span> <b id="username"></b></span>
+                </div>
+                <button class="is-logout" onclick="logout();">
+                    <i class="sign out alternate icon"></i>
+                    <span locale="selector/logout">Log out</span>
+                </button>
+            </footer>
         </div>
+
         <script>
             var interfaceModules = [];
-         $(".ui.checkbox").checkbox();
-          $.get("../../system/users/interfaceinfo", function(data){
-              $("#serviceList").html("");
-              interfaceModules = data;
-              for (var i = 0; i < data.length; i++){
-                  $("#serviceList").append(`<div class="ui segment interfaceModule" name="${data[i].Name}" path="${data[i].StartDir}" onclick="startModule(this);">
-                    <div class="ui grid">
-                        <div class="four wide column" align="right">
-                            <img src="../../${data[i].IconPath}" class="ui tiny image">
-                        </div>
-                        <div class="twelve wide column">
-                            <h2 class="ui header">
-                                ${data[i].Name}
-                                <div class="sub header">${data[i].Desc}</div>
-                            </h2>
+            var applocale = NewAppLocale();
+            //Opened with ?switch (e.g. from a "Switch Services" button): always show the list
+            var forceSelect = new URLSearchParams(window.location.search).has("switch");
+
+            function tr(key, fallback){
+                return applocale.getString(key, fallback);
+            }
+
+            function escapeHTML(text){
+                return $("<div>").text(text == undefined ? "" : text).html();
+            }
+
+            function modulePath(mod){
+                //Desktop registers with an empty StartDir
+                if (mod.Name == "Desktop" || mod.StartDir == ""){
+                    return "../../desktop.html";
+                }
+                return "../../" + mod.StartDir;
+            }
+
+            function renderModules(){
+                var list = $("#serviceList");
+                list.html("");
+                if (interfaceModules.length == 0){
+                    list.html(`<div class="is-empty">${escapeHTML(tr("selector/empty", "No workspace is available for your account. Please contact your administrator."))}</div>`);
+                    return;
+                }
+
+                var remembered = getRemembered();
+                //Keep remembering by default when switching from an already remembered choice
+                $("#remember").prop("checked", remembered != "");
+                interfaceModules.forEach(function(mod, index){
+                    var isDesktop = (mod.Name == "Desktop");
+                    var chip = isDesktop ?
+                        `<span class="is-chip desktop"><i class="desktop icon"></i>${escapeHTML(tr("selector/fulldesktop", "Full desktop"))}</span>` :
+                        `<span class="is-chip"><i class="th icon"></i>${escapeHTML(tr("selector/launcher", "Service launcher"))}</span>`;
+                    var highlight = (remembered == mod.Name || (remembered == "" && index == 0)) ? " highlight" : "";
+                    var desc = isDesktop ? tr("selector/desktopdesc", "Your personal web desktop and files") : mod.Desc;
+                    var card = $(`<button class="is-card${highlight}" type="button">
+                        <div class="is-tile"><img src="../../${escapeHTML(mod.IconPath)}" alt="" onerror="this.src='../../img/system/service.png'"></div>
+                        <div class="is-body">
+                            <div class="is-name">${escapeHTML(mod.Name)}</div>
+                            <div class="is-desc">${escapeHTML(desc)}</div>
+                            ${chip}
                         </div>
-                    </div>
-                </div>`);
-              }
-              useDefaultIfExists();
-          });
-
-        function useDefaultIfExists(){
-            var defaultModule = localStorage.getItem("default-interface-module");
-            if (defaultModule !== undefined && defaultModule !== null && defaultModule !== ""){
-                //Get its path
-                interfaceModules.forEach(mod => {
-                    if (mod.Name == defaultModule){
-                        var targetPath = mod.StartDir;
-                        if (targetPath == ""){
-                            //Redirect to desktop
-                            window.location.href = "../../desktop.html";
-                        }else{
-                            //Redirect to module
-                            window.location.href = "../../" + targetPath;
-                        }
-                    }
+                        <div class="is-go"><svg width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M5 12h14M13 6l6 6-6 6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
+                    </button>`);
+                    card.on("click", function(){
+                        startModule(mod);
+                    });
+                    card.on("mouseenter focus", function(){
+                        $(".is-card.highlight").removeClass("highlight");
+                    });
+                    list.append(card);
                 });
             }
-        }
 
-        function startModule(object){
-            var path = $(object).attr("path");
-            var name = $(object).attr("name");
-            if ($("#remember").checkbox("is checked")){
-                localStorage.setItem("default-interface-module",name)
+            function getRemembered(){
+                try {
+                    return localStorage.getItem("default-interface-module") || "";
+                } catch (e) {
+                    return "";
+                }
             }
-            if (path == ""){
-                //Redirect to desktop
-                window.location.href = "../../desktop.html";
-            }else{
-                //Redirect to module
-                window.location.href = "../../" + path;
+
+            function setRemembered(name){
+                try {
+                    if (name == ""){
+                        localStorage.removeItem("default-interface-module");
+                    }else{
+                        localStorage.setItem("default-interface-module", name);
+                    }
+                } catch (e) {}
+            }
+
+            //Returns true when the browser is being redirected to the remembered interface
+            function useDefaultIfExists(){
+                var defaultModule = getRemembered();
+                if (defaultModule == ""){
+                    return false;
+                }
+                var target = interfaceModules.find(function(mod){ return mod.Name == defaultModule; });
+                if (target == undefined){
+                    //The remembered interface is no longer available to this user
+                    setRemembered("");
+                    return false;
+                }
+                window.location.replace(modulePath(target));
+                return true;
+            }
+
+            function startModule(mod){
+                if ($("#remember").is(":checked")){
+                    setRemembered(mod.Name);
+                }else{
+                    setRemembered("");
+                }
+                window.location.href = modulePath(mod);
+            }
+
+            function loadModules(){
+                $.get("../../system/users/interfaceinfo", function(data){
+                    if (data.error !== undefined){
+                        window.location.href = "../../";
+                        return;
+                    }
+                    interfaceModules = Array.isArray(data) ? data : [];
+                    if (!forceSelect && useDefaultIfExists()){
+                        return;
+                    }
+                    renderModules();
+                });
+            }
+
+            function logout() {
+                $.get("../../system/auth/logout", function() {
+                    window.location.href = "../../";
+                });
             }
-            
-        }
 
-        function logout() {
-            $.get("../../system/auth/logout", function() {
-                window.location.href = "/";
+            $.get("../../system/users/userinfo", function(data){
+                if (data && data.Username){
+                    $("#username").text(data.Username);
+                }
+            });
+
+            $.get("../../system/info/getArOZInfo", function(data){
+                if (data && data.HostName){
+                    $(".hostname").text(data.HostName);
+                }
+            });
+
+            applocale.init("../locale/interface_selector.json", function(){
+                applocale.translate();
+                document.title = tr("selector/title", "Choose your workspace");
+                loadModules();
+            }, function(){
+                loadModules();
             });
-        }
         </script>
     </body>
-</html>
+</html>

+ 242 - 0
src/web/SystemAO/desktop/settings/interface.html

@@ -0,0 +1,242 @@
+<!-- Startup Interface Settings — loaded into SystemAO/system_setting/index.html via jQuery .load() -->
+<style>
+#sif-root {
+    --sif-text:   #1a1a1a;
+    --sif-dim:    #5a5a5a;
+    --sif-muted:  #9a9a9a;
+    --sif-border: rgba(0,0,0,0.10);
+    --sif-hover:  rgba(0,0,0,0.04);
+    --sif-accent: #2f6fed;
+    --sif-accent-soft: rgba(47,111,237,0.08);
+    --sif-green:  #107c10;
+    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
+    font-size: 14px;
+    color: var(--sif-text);
+    padding: 4px 0 32px;
+}
+body.dark #sif-root {
+    --sif-text:   #f0f0f0;
+    --sif-dim:    #b0b0b0;
+    --sif-muted:  #808080;
+    --sif-border: rgba(255,255,255,0.10);
+    --sif-hover:  rgba(255,255,255,0.05);
+    --sif-accent: #6b9bff;
+    --sif-accent-soft: rgba(107,155,255,0.12);
+}
+#sif-root h3.section-title {
+    font-size: 15px;
+    font-weight: 600;
+    color: var(--sif-text);
+    margin: 0 0 4px;
+}
+#sif-root .section-desc {
+    font-size: 12px;
+    color: var(--sif-muted);
+    margin: 0 0 12px;
+}
+#sif-root .sif-section {
+    padding: 16px;
+    border-bottom: 1px solid var(--sif-border);
+}
+#sif-root .sif-section:last-child { border-bottom: none; }
+#sif-root .sif-list {
+    display: flex;
+    flex-direction: column;
+    gap: 6px;
+    max-width: 560px;
+}
+#sif-root .sif-option {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    padding: 10px 12px;
+    border: 1px solid var(--sif-border);
+    border-radius: 6px;
+    cursor: pointer;
+    transition: background-color 0.1s, border-color 0.1s;
+}
+#sif-root .sif-option:hover { background: var(--sif-hover); }
+#sif-root .sif-option.selected {
+    border-color: var(--sif-accent);
+    background: var(--sif-accent-soft);
+}
+#sif-root .sif-option.disabled { cursor: default; }
+#sif-root .sif-radio {
+    flex-shrink: 0;
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    border: 1.5px solid var(--sif-muted);
+    position: relative;
+}
+#sif-root .sif-option.selected .sif-radio { border-color: var(--sif-accent); }
+#sif-root .sif-option.selected .sif-radio::after {
+    content: '';
+    position: absolute;
+    top: 3px; left: 3px;
+    width: 7px; height: 7px;
+    border-radius: 50%;
+    background: var(--sif-accent);
+}
+#sif-root .sif-icon {
+    flex-shrink: 0;
+    width: 32px;
+    height: 32px;
+    object-fit: contain;
+}
+#sif-root .sif-icon-ask {
+    flex-shrink: 0;
+    width: 32px;
+    height: 32px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: var(--sif-dim);
+}
+#sif-root .sif-name { font-size: 13px; font-weight: 600; }
+#sif-root .sif-desc { font-size: 12px; color: var(--sif-muted); }
+#sif-root .sif-note {
+    font-size: 12px;
+    color: var(--sif-dim);
+    margin-top: 10px;
+}
+#sif-root .btn {
+    padding: 5px 12px;
+    border-radius: 4px;
+    border: 1px solid var(--sif-border);
+    background: transparent;
+    color: var(--sif-text);
+    font-size: 12px;
+    cursor: pointer;
+    display: inline-flex;
+    align-items: center;
+    gap: 4px;
+    margin-top: 12px;
+}
+#sif-root .btn:hover { opacity: 0.75; }
+#sif-root .confirm-msg {
+    display: none;
+    margin-top: 8px;
+    padding: 8px 12px;
+    background: rgba(16,124,16,0.1);
+    border-radius: 4px;
+    font-size: 12px;
+    color: var(--sif-green);
+    max-width: 560px;
+}
+body.dark #sif-root .confirm-msg { background: rgba(16,124,16,0.15); }
+</style>
+
+<div id="sif-root">
+    <div class="sif-section">
+        <h3 class="section-title" locale="sif/title">Startup Interface</h3>
+        <p class="section-desc" locale="sif/desc">Choose which workspace opens after you sign in. This setting only applies to this browser.</p>
+        <div id="sif-list" class="sif-list"></div>
+        <div id="sif-single" class="sif-note" style="display:none;" locale="sif/single">Your account has only one workspace, so it always opens after you sign in.</div>
+        <div id="sif-save-confirm" class="confirm-msg"><span locale="sif/saved">Startup interface updated for this browser.</span></div>
+        <button id="sif-open-selector" class="btn" onclick="sifOpenSelector()" style="display:none;">
+            <svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M2 5h10M9 2l3 3-3 3M14 11H4M7 8l-3 3 3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
+            <span locale="sif/switch">Switch Workspace Now</span>
+        </button>
+    </div>
+</div>
+
+<script>
+(function () {
+    var sifLocale = NewAppLocale();
+    var sifStorageKey = "default-interface-module";
+    var sifModules = [];
+
+    sifLocale.init("../locale/system_settings/desktop.json", function () {
+        sifLocale.translate();
+        sifLoadModules();
+    }, function () {
+        sifLoadModules();
+    });
+
+    function sifEsc(text) {
+        return $("<div>").text(text == undefined ? "" : text).html();
+    }
+
+    function sifGetRemembered() {
+        try {
+            return localStorage.getItem(sifStorageKey) || "";
+        } catch (e) {
+            return "";
+        }
+    }
+
+    function sifSetRemembered(name) {
+        try {
+            if (name === "") {
+                localStorage.removeItem(sifStorageKey);
+            } else {
+                localStorage.setItem(sifStorageKey, name);
+            }
+            return true;
+        } catch (e) {
+            return false;
+        }
+    }
+
+    function sifLoadModules() {
+        $.get("../../system/users/interfaceinfo", function (data) {
+            sifModules = Array.isArray(data) ? data : [];
+            sifRender();
+        });
+    }
+
+    function sifRender() {
+        var list = $("#sif-list");
+        list.html("");
+        var remembered = sifGetRemembered();
+        if (remembered !== "" && !sifModules.some(function (m) { return m.Name === remembered; })) {
+            //The remembered interface is no longer available to this user
+            remembered = "";
+        }
+
+        if (sifModules.length <= 1) {
+            //The server opens the only interface directly, the browser choice is never used
+            sifModules.forEach(function (m) {
+                list.append(sifOptionHTML(m.Name, m.Name, m.Desc, "../../" + m.IconPath, true));
+            });
+            list.find(".sif-option").addClass("disabled");
+            $("#sif-single").show();
+            return;
+        }
+
+        list.append(sifOptionHTML("",
+            sifLocale.getString("sif/ask", "Ask me every time"),
+            sifLocale.getString("sif/ask-desc", "Show the workspace selector after signing in"),
+            "", remembered === ""));
+        sifModules.forEach(function (m) {
+            list.append(sifOptionHTML(m.Name, m.Name, m.Desc, "../../" + m.IconPath, remembered === m.Name));
+        });
+        $("#sif-open-selector").show();
+
+        list.find(".sif-option").on("click", function () {
+            var value = $(this).attr("data-value");
+            if (!sifSetRemembered(value)) {
+                return;
+            }
+            list.find(".sif-option").removeClass("selected");
+            $(this).addClass("selected");
+            $("#sif-save-confirm").stop(true).finish().slideDown("fast").delay(3000).slideUp("fast");
+        });
+    }
+
+    function sifOptionHTML(value, name, desc, icon, selected) {
+        var iconHTML = icon === "" ?
+            '<div class="sif-icon-ask"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><rect x="3" y="4" width="18" height="16" rx="2.5" stroke="currentColor" stroke-width="1.6"/><path d="M7 9h10M7 13h6" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></div>' :
+            '<img class="sif-icon" src="' + sifEsc(icon) + '" alt="" onerror="this.src=\'../../img/system/service.png\'">';
+        return '<div class="sif-option' + (selected ? ' selected' : '') + '" data-value="' + sifEsc(value) + '">' +
+            '<div class="sif-radio"></div>' + iconHTML +
+            '<div><div class="sif-name">' + sifEsc(name) + '</div><div class="sif-desc">' + sifEsc(desc) + '</div></div>' +
+            '</div>';
+    }
+
+    window.sifOpenSelector = function () {
+        window.top.location.href = new URL("../boot/interface_selector.html?switch", window.location.href).href;
+    };
+}());
+</script>

+ 114 - 0
src/web/SystemAO/locale/interface_selector.json

@@ -0,0 +1,114 @@
+{
+    "author": "tobychui",
+    "version": "1.0",
+    "keys": {
+        "en-us": {
+            "name": "English (US)",
+            "fwtitle": "",
+            "strings": {
+                "selector/title": "Choose your workspace",
+                "selector/subtitle": "Select a service to continue",
+                "selector/remember": "Remember my choice on this browser",
+                "selector/hint": "You can change this setting later in System Settings.",
+                "selector/signedin": "Signed in as",
+                "selector/logout": "Log out",
+                "selector/fulldesktop": "Full desktop",
+                "selector/launcher": "Service launcher",
+                "selector/desktopdesc": "Your personal web desktop and files",
+                "selector/empty": "No workspace is available for your account. Please contact your administrator."
+            },
+            "titles": {},
+            "placeholder": {}
+        },
+        "zh-tw": {
+            "name": "繁體中文(台灣)",
+            "fwtitle": "",
+            "strings": {
+                "selector/title": "選擇你的工作區",
+                "selector/subtitle": "選擇一項服務以繼續",
+                "selector/remember": "在此瀏覽器記住我的選擇",
+                "selector/hint": "你可以稍後在系統設定中更改此設定。",
+                "selector/signedin": "登入身分",
+                "selector/logout": "登出",
+                "selector/fulldesktop": "完整桌面",
+                "selector/launcher": "服務啟動器",
+                "selector/desktopdesc": "你的個人網頁桌面與檔案",
+                "selector/empty": "你的帳戶沒有可用的工作區,請聯絡系統管理員。"
+            },
+            "titles": {},
+            "placeholder": {}
+        },
+        "zh-hk": {
+            "name": "繁體中文(香港)",
+            "fwtitle": "",
+            "strings": {
+                "selector/title": "選擇你的工作區",
+                "selector/subtitle": "選擇一項服務以繼續",
+                "selector/remember": "在此瀏覽器記住我的選擇",
+                "selector/hint": "你可以稍後在系統設定中更改此設定。",
+                "selector/signedin": "登入身分",
+                "selector/logout": "登出",
+                "selector/fulldesktop": "完整桌面",
+                "selector/launcher": "服務啟動器",
+                "selector/desktopdesc": "你的個人網頁桌面與檔案",
+                "selector/empty": "你的帳戶沒有可用的工作區,請聯絡系統管理員。"
+            },
+            "titles": {},
+            "placeholder": {}
+        },
+        "zh-cn": {
+            "name": "简体中文",
+            "fwtitle": "",
+            "strings": {
+                "selector/title": "选择你的工作区",
+                "selector/subtitle": "选择一项服务以继续",
+                "selector/remember": "在此浏览器记住我的选择",
+                "selector/hint": "你可以稍后在系统设置中更改此设置。",
+                "selector/signedin": "登录身份",
+                "selector/logout": "退出登录",
+                "selector/fulldesktop": "完整桌面",
+                "selector/launcher": "服务启动器",
+                "selector/desktopdesc": "你的个人网页桌面与文件",
+                "selector/empty": "你的账户没有可用的工作区,请联系系统管理员。"
+            },
+            "titles": {},
+            "placeholder": {}
+        },
+        "ja-jp": {
+            "name": "日本語",
+            "fwtitle": "",
+            "strings": {
+                "selector/title": "ワークスペースを選択",
+                "selector/subtitle": "続行するサービスを選択してください",
+                "selector/remember": "このブラウザで選択を記憶する",
+                "selector/hint": "この設定は後でシステム設定から変更できます。",
+                "selector/signedin": "サインイン中:",
+                "selector/logout": "ログアウト",
+                "selector/fulldesktop": "フルデスクトップ",
+                "selector/launcher": "サービスランチャー",
+                "selector/desktopdesc": "あなた専用のウェブデスクトップとファイル",
+                "selector/empty": "このアカウントで利用できるワークスペースがありません。管理者にお問い合わせください。"
+            },
+            "titles": {},
+            "placeholder": {}
+        },
+        "ko-kr": {
+            "name": "한국어",
+            "fwtitle": "",
+            "strings": {
+                "selector/title": "작업 공간 선택",
+                "selector/subtitle": "계속할 서비스를 선택하세요",
+                "selector/remember": "이 브라우저에서 선택 기억하기",
+                "selector/hint": "이 설정은 나중에 시스템 설정에서 변경할 수 있습니다.",
+                "selector/signedin": "로그인 계정:",
+                "selector/logout": "로그아웃",
+                "selector/fulldesktop": "전체 데스크톱",
+                "selector/launcher": "서비스 런처",
+                "selector/desktopdesc": "나만의 웹 데스크톱과 파일",
+                "selector/empty": "이 계정에서 사용할 수 있는 작업 공간이 없습니다. 관리자에게 문의하세요."
+            },
+            "titles": {},
+            "placeholder": {}
+        }
+    }
+}

+ 518 - 7
src/web/SystemAO/locale/system_settings.json

@@ -71,7 +71,80 @@
                 "tab/about/Open Source": "開源元件",
                 "tab/about/License": "系統授權",
                 "tab/about/Vendor": "供應商",
-                "": ""
+                "": "",
+                "menu/group/AI Integration": "AI 整合",
+                "menu/group/Containers": "容器",
+                "tab/desktop/Startup Interface": "啟動介面",
+                "tab/desktop/Notifications": "通知",
+                "tab/disk/RAID": "RAID 磁碟陣列",
+                "tab/disk/File Manager": "檔案管理器",
+                "tab/network/Screen Share Relay": "螢幕分享中繼",
+                "tab/advance/AGI Runtimes": "AGI 執行個體",
+                "tab/advance/Shared Spaces": "共享空間",
+                "tab/ainteg/AI Model": "AI 模型",
+                "tab/ainteg/CNN Inference": "CNN 影像推論",
+                "tab/container/Docker Daemon": "Docker 服務",
+                "tab/container/Docker Engine": "Docker 引擎",
+                "tab/container/Docker List": "容器列表",
+                "desc/advance/AGI Runtimes": "監控並強制停止執行中的 AGI 腳本虛擬機器",
+                "desc/ainteg/AI Model": "設定相容 OpenAI / Anthropic 的端點、計價、配額並檢視權杖用量",
+                "desc/security/Connection Log": "登入嘗試記錄",
+                "desc/security/Access Control": "禁止或允許特定 IP 範圍登入",
+                "desc/network/Screen Share Relay": "內建 TURN 中繼,讓 Arozcast 螢幕分享可透過網際網路進行",
+                "desc/cluster/Cluster Settings": "建立或加入叢集,並設定其儲存與排程",
+                "desc/cluster/Cluster Info": "此節點、對等節點、複寫與排程的健康狀態",
+                "desc/cluster/Cluster Jobs": "在叢集中任一節點上執行腳本",
+                "desc/cluster/Neighbourhood": "附近可組成叢集的 ArOZ 主機",
+                "desc/ainteg/CNN Inference": "設定外部 CXNNAIO 視覺推論伺服器,用於影像與人臉辨識",
+                "desc/desktop/Wallpaper": "桌面桌布設定",
+                "desc/desktop/Sounds": "系統音效設定",
+                "desc/desktop/Theme": "系統主題色彩",
+                "desc/desktop/Mobile UX": "行動桌面捷徑",
+                "desc/desktop/Startup Interface": "登入後開啟的工作區",
+                "desc/desktop/Notifications": "選擇通知的接收方式並設定傳送代理",
+                "desc/device/Client Device": "你正在使用的瀏覽器詳細資訊",
+                "desc/device/Device Testing": "音訊、顯示、鍵盤、滑鼠及觸控測試",
+                "desc/device/Language": "設定系統的顯示語言",
+                "desc/disk/Disk Space": "磁碟上的系統儲存空間",
+                "desc/disk/Disk SMART": "硬碟健康檢查",
+                "desc/disk/RAID": "提供基本的 mdadm 功能",
+                "desc/container/Docker Daemon": "啟動、停止及設定 Docker 服務",
+                "desc/container/Docker Engine": "Docker 版本、服務狀態、磁碟用量與清理",
+                "desc/container/Docker List": "執行中容器總覽,並可快速開啟 Docker 管理員",
+                "desc/disk/File Manager": "資源回收筒的保留時間與大小",
+                "desc/info/Power": "設定主機裝置的電源狀態",
+                "desc/device/IoT Hub": "管理 IoT 裝置掃描器",
+                "desc/security/LDAP": "允許外部帳戶存取系統",
+                "desc/module/Module List": "目前已載入系統的模組列表",
+                "desc/module/Default Module": "開啟檔案時使用的預設模組",
+                "desc/module/Subservices": "啟動及終止子服務",
+                "desc/module/Add & Remove Module": "在系統中安裝及移除模組",
+                "desc/network/Port Forward": "以 UPnP 為基礎的連接埠轉送",
+                "desc/network/Network Info": "網路資訊",
+                "desc/network/Personal Page": "個人網頁",
+                "desc/network/File Servers": "網路檔案傳輸伺服器",
+                "desc/security/OAuth": "使用任何相容 OIDC 的身分提供者登入",
+                "desc/users/Permission Groups": "管理群組的存取權限",
+                "desc/disk/Storage Quota": "使用者剩餘空間",
+                "desc/users/Public Registry": "允許公開使用者在此主機建立帳戶",
+                "desc/cluster/Tasks Scheduler": "系統工作與執行排程器",
+                "desc/advance/Auto Login Mode": "允許機器人自動登入系統",
+                "desc/advance/Disk Manager": "掛載、卸載及格式化本機磁碟",
+                "desc/advance/Shared Spaces": "協作空間:儲存、限制與清理",
+                "desc/info/Runtime": "在執行期間變更啟動參數",
+                "desc/disk/Storage Pools": "儲存池掛載設定",
+                "desc/about/ArozOS": "關於此 ArozOS",
+                "desc/about/Open Source": "來自開源社群的授權條款",
+                "desc/about/License": "ArozOS 的授權條款",
+                "desc/about/Vendor": "供應商說明",
+                "desc/info/Host Info": "系統資訊",
+                "desc/info/Performance": "系統 CPU 與記憶體使用量",
+                "desc/info/Updates": "執行 ArozOS 更新",
+                "desc/advance/System Log": "檢視 ArozOS 系統記錄",
+                "desc/users/My Account": "管理你的帳戶與密碼",
+                "desc/users/User List": "在此系統註冊的使用者列表",
+                "desc/network/WiFi Info": "目前連線的 WiFi 資訊",
+                "desc/network/WiFi Settings": "設定 WiFi 連線"
             },
             "titles": {
                 "Config and info about the Server Host": "伺服器設定與資訊",
@@ -195,7 +268,80 @@
                 "tab/about/Open Source": "開源元件",
                 "tab/about/License": "系統授權",
                 "tab/about/Vendor": "供應商",
-                "": ""
+                "": "",
+                "menu/group/AI Integration": "AI 整合",
+                "menu/group/Containers": "容器",
+                "tab/desktop/Startup Interface": "啟動介面",
+                "tab/desktop/Notifications": "通知",
+                "tab/disk/RAID": "RAID 磁碟陣列",
+                "tab/disk/File Manager": "檔案管理器",
+                "tab/network/Screen Share Relay": "螢幕分享中繼",
+                "tab/advance/AGI Runtimes": "AGI 執行個體",
+                "tab/advance/Shared Spaces": "共享空間",
+                "tab/ainteg/AI Model": "AI 模型",
+                "tab/ainteg/CNN Inference": "CNN 影像推論",
+                "tab/container/Docker Daemon": "Docker 服務",
+                "tab/container/Docker Engine": "Docker 引擎",
+                "tab/container/Docker List": "容器列表",
+                "desc/advance/AGI Runtimes": "監控並強制停止執行中的 AGI 腳本虛擬機器",
+                "desc/ainteg/AI Model": "設定相容 OpenAI / Anthropic 的端點、計價、配額並檢視權杖用量",
+                "desc/security/Connection Log": "登入嘗試記錄",
+                "desc/security/Access Control": "禁止或允許特定 IP 範圍登入",
+                "desc/network/Screen Share Relay": "內建 TURN 中繼,讓 Arozcast 螢幕分享可透過網際網路進行",
+                "desc/cluster/Cluster Settings": "建立或加入叢集,並設定其儲存與排程",
+                "desc/cluster/Cluster Info": "此節點、對等節點、複寫與排程的健康狀態",
+                "desc/cluster/Cluster Jobs": "在叢集中任一節點上執行腳本",
+                "desc/cluster/Neighbourhood": "附近可組成叢集的 ArOZ 主機",
+                "desc/ainteg/CNN Inference": "設定外部 CXNNAIO 視覺推論伺服器,用於影像與人臉辨識",
+                "desc/desktop/Wallpaper": "桌面桌布設定",
+                "desc/desktop/Sounds": "系統音效設定",
+                "desc/desktop/Theme": "系統主題色彩",
+                "desc/desktop/Mobile UX": "行動桌面捷徑",
+                "desc/desktop/Startup Interface": "登入後開啟的工作區",
+                "desc/desktop/Notifications": "選擇通知的接收方式並設定傳送代理",
+                "desc/device/Client Device": "你正在使用的瀏覽器詳細資訊",
+                "desc/device/Device Testing": "音訊、顯示、鍵盤、滑鼠及觸控測試",
+                "desc/device/Language": "設定系統的顯示語言",
+                "desc/disk/Disk Space": "磁碟上的系統儲存空間",
+                "desc/disk/Disk SMART": "硬碟健康檢查",
+                "desc/disk/RAID": "提供基本的 mdadm 功能",
+                "desc/container/Docker Daemon": "啟動、停止及設定 Docker 服務",
+                "desc/container/Docker Engine": "Docker 版本、服務狀態、磁碟用量與清理",
+                "desc/container/Docker List": "執行中容器總覽,並可快速開啟 Docker 管理員",
+                "desc/disk/File Manager": "資源回收筒的保留時間與大小",
+                "desc/info/Power": "設定主機裝置的電源狀態",
+                "desc/device/IoT Hub": "管理 IoT 裝置掃描器",
+                "desc/security/LDAP": "允許外部帳戶存取系統",
+                "desc/module/Module List": "目前已載入系統的模組列表",
+                "desc/module/Default Module": "開啟檔案時使用的預設模組",
+                "desc/module/Subservices": "啟動及終止子服務",
+                "desc/module/Add & Remove Module": "在系統中安裝及移除模組",
+                "desc/network/Port Forward": "以 UPnP 為基礎的連接埠轉送",
+                "desc/network/Network Info": "網路資訊",
+                "desc/network/Personal Page": "個人網頁",
+                "desc/network/File Servers": "網路檔案傳輸伺服器",
+                "desc/security/OAuth": "使用任何相容 OIDC 的身分提供者登入",
+                "desc/users/Permission Groups": "管理群組的存取權限",
+                "desc/disk/Storage Quota": "使用者剩餘空間",
+                "desc/users/Public Registry": "允許公開使用者在此主機建立帳戶",
+                "desc/cluster/Tasks Scheduler": "系統工作與執行排程器",
+                "desc/advance/Auto Login Mode": "允許機器人自動登入系統",
+                "desc/advance/Disk Manager": "掛載、卸載及格式化本機磁碟",
+                "desc/advance/Shared Spaces": "協作空間:儲存、限制與清理",
+                "desc/info/Runtime": "在執行期間變更啟動參數",
+                "desc/disk/Storage Pools": "儲存池掛載設定",
+                "desc/about/ArozOS": "關於此 ArozOS",
+                "desc/about/Open Source": "來自開源社群的授權條款",
+                "desc/about/License": "ArozOS 的授權條款",
+                "desc/about/Vendor": "供應商說明",
+                "desc/info/Host Info": "系統資訊",
+                "desc/info/Performance": "系統 CPU 與記憶體使用量",
+                "desc/info/Updates": "執行 ArozOS 更新",
+                "desc/advance/System Log": "檢視 ArozOS 系統記錄",
+                "desc/users/My Account": "管理你的帳戶與密碼",
+                "desc/users/User List": "在此系統註冊的使用者列表",
+                "desc/network/WiFi Info": "目前連線的 WiFi 資訊",
+                "desc/network/WiFi Settings": "設定 WiFi 連線"
             },
             "titles": {
                 "Config and info about the Server Host": "伺服器設定與資訊",
@@ -318,7 +464,80 @@
                 "tab/about/Open Source": "开源",
                 "tab/about/License": "系统授权",
                 "tab/about/Vendor": "供应商",
-                "": ""
+                "": "",
+                "menu/group/AI Integration": "AI 集成",
+                "menu/group/Containers": "容器",
+                "tab/desktop/Startup Interface": "启动界面",
+                "tab/desktop/Notifications": "通知",
+                "tab/disk/RAID": "RAID 磁盘阵列",
+                "tab/disk/File Manager": "文件管理器",
+                "tab/network/Screen Share Relay": "屏幕共享中继",
+                "tab/advance/AGI Runtimes": "AGI 运行实例",
+                "tab/advance/Shared Spaces": "共享空间",
+                "tab/ainteg/AI Model": "AI 模型",
+                "tab/ainteg/CNN Inference": "CNN 图像推理",
+                "tab/container/Docker Daemon": "Docker 服务",
+                "tab/container/Docker Engine": "Docker 引擎",
+                "tab/container/Docker List": "容器列表",
+                "desc/advance/AGI Runtimes": "监控并强制停止运行中的 AGI 脚本虚拟机",
+                "desc/ainteg/AI Model": "配置兼容 OpenAI / Anthropic 的端点、计价、配额并查看令牌用量",
+                "desc/security/Connection Log": "登录尝试日志",
+                "desc/security/Access Control": "禁止或允许特定 IP 范围登录",
+                "desc/network/Screen Share Relay": "内置 TURN 中继,让 Arozcast 屏幕共享可通过互联网进行",
+                "desc/cluster/Cluster Settings": "创建或加入集群,并配置其存储与调度",
+                "desc/cluster/Cluster Info": "此节点、对等节点、复制与调度的健康状态",
+                "desc/cluster/Cluster Jobs": "在集群中任一节点上运行脚本",
+                "desc/cluster/Neighbourhood": "附近可组成集群的 ArOZ 主机",
+                "desc/ainteg/CNN Inference": "配置外部 CXNNAIO 视觉推理服务器,用于图像与人脸识别",
+                "desc/desktop/Wallpaper": "桌面壁纸设置",
+                "desc/desktop/Sounds": "系统音效设置",
+                "desc/desktop/Theme": "系统主题颜色",
+                "desc/desktop/Mobile UX": "移动桌面快捷方式",
+                "desc/desktop/Startup Interface": "登录后打开的工作区",
+                "desc/desktop/Notifications": "选择通知的接收方式并配置发送代理",
+                "desc/device/Client Device": "你正在使用的浏览器详细信息",
+                "desc/device/Device Testing": "音频、显示、键盘、鼠标及触控测试",
+                "desc/device/Language": "设置系统的显示语言",
+                "desc/disk/Disk Space": "磁盘上的系统存储空间",
+                "desc/disk/Disk SMART": "硬盘健康检查",
+                "desc/disk/RAID": "提供基本的 mdadm 功能",
+                "desc/container/Docker Daemon": "启动、停止及配置 Docker 服务",
+                "desc/container/Docker Engine": "Docker 版本、服务状态、磁盘用量与清理",
+                "desc/container/Docker List": "运行中容器总览,并可快速打开 Docker 管理器",
+                "desc/disk/File Manager": "回收站的保留时间与大小",
+                "desc/info/Power": "设置主机设备的电源状态",
+                "desc/device/IoT Hub": "管理 IoT 设备扫描器",
+                "desc/security/LDAP": "允许外部账户访问系统",
+                "desc/module/Module List": "当前已加载到系统的模块列表",
+                "desc/module/Default Module": "打开文件时使用的默认模块",
+                "desc/module/Subservices": "启动及终止子服务",
+                "desc/module/Add & Remove Module": "在系统中安装及移除模块",
+                "desc/network/Port Forward": "基于 UPnP 的端口转发",
+                "desc/network/Network Info": "网络信息",
+                "desc/network/Personal Page": "个人网页",
+                "desc/network/File Servers": "网络文件传输服务器",
+                "desc/security/OAuth": "使用任何兼容 OIDC 的身份提供者登录",
+                "desc/users/Permission Groups": "管理群组的访问权限",
+                "desc/disk/Storage Quota": "用户剩余空间",
+                "desc/users/Public Registry": "允许公开用户在此主机创建账户",
+                "desc/cluster/Tasks Scheduler": "系统任务与执行调度器",
+                "desc/advance/Auto Login Mode": "允许机器人自动登录系统",
+                "desc/advance/Disk Manager": "挂载、卸载及格式化本地磁盘",
+                "desc/advance/Shared Spaces": "协作空间:存储、限制与清理",
+                "desc/info/Runtime": "在运行时更改启动参数",
+                "desc/disk/Storage Pools": "存储池挂载配置",
+                "desc/about/ArozOS": "关于此 ArozOS",
+                "desc/about/Open Source": "来自开源社区的许可证",
+                "desc/about/License": "ArozOS 的许可证",
+                "desc/about/Vendor": "供应商说明",
+                "desc/info/Host Info": "系统信息",
+                "desc/info/Performance": "系统 CPU 与内存使用量",
+                "desc/info/Updates": "执行 ArozOS 更新",
+                "desc/advance/System Log": "查看 ArozOS 系统日志",
+                "desc/users/My Account": "管理你的账户与密码",
+                "desc/users/User List": "在此系统注册的用户列表",
+                "desc/network/WiFi Info": "当前连接的 WiFi 信息",
+                "desc/network/WiFi Settings": "设置 WiFi 连接"
             },
             "titles": {
                 "Config and info about the Server Host": "服务器设置与信息",
@@ -442,7 +661,80 @@
                 "tab/about/Open Source": "Open Source Components",
                 "tab/about/License": "System License",
                 "tab/about/Vendor": "Vendor",
-                "": ""
+                "": "",
+                "menu/group/AI Integration": "AI Integration",
+                "menu/group/Containers": "Containers",
+                "tab/desktop/Startup Interface": "Startup Interface",
+                "tab/desktop/Notifications": "Notifications",
+                "tab/disk/RAID": "RAID",
+                "tab/disk/File Manager": "File Manager",
+                "tab/network/Screen Share Relay": "Screen Share Relay",
+                "tab/advance/AGI Runtimes": "AGI Runtimes",
+                "tab/advance/Shared Spaces": "Shared Spaces",
+                "tab/ainteg/AI Model": "AI Model",
+                "tab/ainteg/CNN Inference": "CNN Inference",
+                "tab/container/Docker Daemon": "Docker Daemon",
+                "tab/container/Docker Engine": "Docker Engine",
+                "tab/container/Docker List": "Docker List",
+                "desc/advance/AGI Runtimes": "Monitor and force-stop running AGI script VM instances",
+                "desc/ainteg/AI Model": "Configure an OpenAI / Anthropic compatible endpoint, pricing, quota and view token usage",
+                "desc/security/Connection Log": "Logs for login attempts",
+                "desc/security/Access Control": "Prevent / Allow certain IP ranges from logging in",
+                "desc/network/Screen Share Relay": "Built-in TURN relay for Arozcast screen share over the Internet",
+                "desc/cluster/Cluster Settings": "Create or join a cluster and set up its storage and scheduling",
+                "desc/cluster/Cluster Info": "Health of this node, its peers, replication and scheduling",
+                "desc/cluster/Cluster Jobs": "Run scripts on any node of the cluster",
+                "desc/cluster/Neighbourhood": "Nearby ArOZ Host for Clustering",
+                "desc/ainteg/CNN Inference": "Configure an external CXNNAIO vision-inference server for image/face recognition",
+                "desc/desktop/Wallpaper": "Desktop Wallpaper Settings",
+                "desc/desktop/Sounds": "System Sound Settings",
+                "desc/desktop/Theme": "System Theme Color",
+                "desc/desktop/Mobile UX": "Mobile Desktop Shortcuts",
+                "desc/desktop/Startup Interface": "Workspace opened after sign in",
+                "desc/desktop/Notifications": "Choose how you receive notifications and configure delivery agents",
+                "desc/device/Client Device": "Detail about the browser you are using",
+                "desc/device/Device Testing": "Audio, display, keyboard, mouse and touch testing",
+                "desc/device/Language": "Set the display language of the system",
+                "desc/disk/Disk Space": "System Storage Space on Disks",
+                "desc/disk/Disk SMART": "HardDisk Health Checking",
+                "desc/disk/RAID": "Providing basic mdadm features",
+                "desc/container/Docker Daemon": "Start, stop and configure the Docker daemon service",
+                "desc/container/Docker Engine": "Docker version, daemon status, disk usage and cleanup",
+                "desc/container/Docker List": "Running containers overview and quick access to Docker Manager",
+                "desc/disk/File Manager": "Trash Bin Retention and Size",
+                "desc/info/Power": "Set the power state of the host device",
+                "desc/device/IoT Hub": "Manage IoT Devices Scanners",
+                "desc/security/LDAP": "Allows external account access to system",
+                "desc/module/Module List": "A list of module currently loaded in the system",
+                "desc/module/Default Module": "Default module use to open a file",
+                "desc/module/Subservices": "Launch and kill subservices",
+                "desc/module/Add & Remove Module": "Install & Remove Module to the system",
+                "desc/network/Port Forward": "UPnP based port forwarding",
+                "desc/network/Network Info": "Network Information",
+                "desc/network/Personal Page": "Personal Web Page",
+                "desc/network/File Servers": "Network File Transfer Servers",
+                "desc/security/OAuth": "Sign in with any OIDC-compatible identity provider",
+                "desc/users/Permission Groups": "Handle the permission of access in groups",
+                "desc/disk/Storage Quota": "User Remaining Space",
+                "desc/users/Public Registry": "Allow public users to create account in this host",
+                "desc/cluster/Tasks Scheduler": "System Tasks and Execution Scheduler",
+                "desc/advance/Auto Login Mode": "Allow bots logging into the system automatically",
+                "desc/advance/Disk Manager": "Mount, Unmount and Formatting Local Disks",
+                "desc/advance/Shared Spaces": "Collaboration spaces: storage, limits and cleanup",
+                "desc/info/Runtime": "Change startup parameters at runtime",
+                "desc/disk/Storage Pools": "Storage Pool Mounting Configuration",
+                "desc/about/ArozOS": "About this ArozOS",
+                "desc/about/Open Source": "License from the Open Source Community",
+                "desc/about/License": "License of ArozOS",
+                "desc/about/Vendor": "Vendor Notes",
+                "desc/info/Host Info": "System Information",
+                "desc/info/Performance": "System CPU and RAM usage",
+                "desc/info/Updates": "Perform ArozOS Updates",
+                "desc/advance/System Log": "View ArozOS System Log",
+                "desc/users/My Account": "Manage your account and password",
+                "desc/users/User List": "A list of users registered on this system",
+                "desc/network/WiFi Info": "Current Connected WiFi Information",
+                "desc/network/WiFi Settings": "Set up WiFi connections"
             },
             "titles": {
                 "Config and info about the Server Host": "Server Configuration and Information",
@@ -565,7 +857,80 @@
                 "tab/about/Open Source": "Open Source Components",
                 "tab/about/License": "System License",
                 "tab/about/Vendor": "Vendor",
-                "": ""
+                "": "",
+                "menu/group/AI Integration": "AI Integration",
+                "menu/group/Containers": "Containers",
+                "tab/desktop/Startup Interface": "Startup Interface",
+                "tab/desktop/Notifications": "Notifications",
+                "tab/disk/RAID": "RAID",
+                "tab/disk/File Manager": "File Manager",
+                "tab/network/Screen Share Relay": "Screen Share Relay",
+                "tab/advance/AGI Runtimes": "AGI Runtimes",
+                "tab/advance/Shared Spaces": "Shared Spaces",
+                "tab/ainteg/AI Model": "AI Model",
+                "tab/ainteg/CNN Inference": "CNN Inference",
+                "tab/container/Docker Daemon": "Docker Daemon",
+                "tab/container/Docker Engine": "Docker Engine",
+                "tab/container/Docker List": "Docker List",
+                "desc/advance/AGI Runtimes": "Monitor and force-stop running AGI script VM instances",
+                "desc/ainteg/AI Model": "Configure an OpenAI / Anthropic compatible endpoint, pricing, quota and view token usage",
+                "desc/security/Connection Log": "Logs for login attempts",
+                "desc/security/Access Control": "Prevent / Allow certain IP ranges from logging in",
+                "desc/network/Screen Share Relay": "Built-in TURN relay for Arozcast screen share over the Internet",
+                "desc/cluster/Cluster Settings": "Create or join a cluster and set up its storage and scheduling",
+                "desc/cluster/Cluster Info": "Health of this node, its peers, replication and scheduling",
+                "desc/cluster/Cluster Jobs": "Run scripts on any node of the cluster",
+                "desc/cluster/Neighbourhood": "Nearby ArOZ Host for Clustering",
+                "desc/ainteg/CNN Inference": "Configure an external CXNNAIO vision-inference server for image/face recognition",
+                "desc/desktop/Wallpaper": "Desktop Wallpaper Settings",
+                "desc/desktop/Sounds": "System Sound Settings",
+                "desc/desktop/Theme": "System Theme Color",
+                "desc/desktop/Mobile UX": "Mobile Desktop Shortcuts",
+                "desc/desktop/Startup Interface": "Workspace opened after sign in",
+                "desc/desktop/Notifications": "Choose how you receive notifications and configure delivery agents",
+                "desc/device/Client Device": "Detail about the browser you are using",
+                "desc/device/Device Testing": "Audio, display, keyboard, mouse and touch testing",
+                "desc/device/Language": "Set the display language of the system",
+                "desc/disk/Disk Space": "System Storage Space on Disks",
+                "desc/disk/Disk SMART": "HardDisk Health Checking",
+                "desc/disk/RAID": "Providing basic mdadm features",
+                "desc/container/Docker Daemon": "Start, stop and configure the Docker daemon service",
+                "desc/container/Docker Engine": "Docker version, daemon status, disk usage and cleanup",
+                "desc/container/Docker List": "Running containers overview and quick access to Docker Manager",
+                "desc/disk/File Manager": "Trash Bin Retention and Size",
+                "desc/info/Power": "Set the power state of the host device",
+                "desc/device/IoT Hub": "Manage IoT Devices Scanners",
+                "desc/security/LDAP": "Allows external account access to system",
+                "desc/module/Module List": "A list of module currently loaded in the system",
+                "desc/module/Default Module": "Default module use to open a file",
+                "desc/module/Subservices": "Launch and kill subservices",
+                "desc/module/Add & Remove Module": "Install & Remove Module to the system",
+                "desc/network/Port Forward": "UPnP based port forwarding",
+                "desc/network/Network Info": "Network Information",
+                "desc/network/Personal Page": "Personal Web Page",
+                "desc/network/File Servers": "Network File Transfer Servers",
+                "desc/security/OAuth": "Sign in with any OIDC-compatible identity provider",
+                "desc/users/Permission Groups": "Handle the permission of access in groups",
+                "desc/disk/Storage Quota": "User Remaining Space",
+                "desc/users/Public Registry": "Allow public users to create account in this host",
+                "desc/cluster/Tasks Scheduler": "System Tasks and Execution Scheduler",
+                "desc/advance/Auto Login Mode": "Allow bots logging into the system automatically",
+                "desc/advance/Disk Manager": "Mount, Unmount and Formatting Local Disks",
+                "desc/advance/Shared Spaces": "Collaboration spaces: storage, limits and cleanup",
+                "desc/info/Runtime": "Change startup parameters at runtime",
+                "desc/disk/Storage Pools": "Storage Pool Mounting Configuration",
+                "desc/about/ArozOS": "About this ArozOS",
+                "desc/about/Open Source": "License from the Open Source Community",
+                "desc/about/License": "License of ArozOS",
+                "desc/about/Vendor": "Vendor Notes",
+                "desc/info/Host Info": "System Information",
+                "desc/info/Performance": "System CPU and RAM usage",
+                "desc/info/Updates": "Perform ArozOS Updates",
+                "desc/advance/System Log": "View ArozOS System Log",
+                "desc/users/My Account": "Manage your account and password",
+                "desc/users/User List": "A list of users registered on this system",
+                "desc/network/WiFi Info": "Current Connected WiFi Information",
+                "desc/network/WiFi Settings": "Set up WiFi connections"
             },
             "titles": {
                 "Config and info about the Server Host": "Server Configuration and Information",
@@ -688,7 +1053,80 @@
                 "tab/about/Open Source": "オープンソースコンポーネント",
                 "tab/about/License": "システムライセンス",
                 "tab/about/Vendor": "ベンダー",
-                "": ""
+                "": "",
+                "menu/group/AI Integration": "AI連携",
+                "menu/group/Containers": "コンテナー",
+                "tab/desktop/Startup Interface": "起動インターフェース",
+                "tab/desktop/Notifications": "通知",
+                "tab/disk/RAID": "RAIDアレイ",
+                "tab/disk/File Manager": "ファイルマネージャー",
+                "tab/network/Screen Share Relay": "画面共有リレー",
+                "tab/advance/AGI Runtimes": "AGI実行インスタンス",
+                "tab/advance/Shared Spaces": "共有スペース",
+                "tab/ainteg/AI Model": "AIモデル",
+                "tab/ainteg/CNN Inference": "CNN画像推論",
+                "tab/container/Docker Daemon": "Dockerデーモン",
+                "tab/container/Docker Engine": "Dockerエンジン",
+                "tab/container/Docker List": "コンテナー一覧",
+                "desc/advance/AGI Runtimes": "実行中の AGI スクリプト VM を監視・強制停止",
+                "desc/ainteg/AI Model": "OpenAI / Anthropic 互換エンドポイント、料金、クォータの設定とトークン使用量の確認",
+                "desc/security/Connection Log": "ログイン試行の記録",
+                "desc/security/Access Control": "特定の IP 範囲からのログインを拒否 / 許可",
+                "desc/network/Screen Share Relay": "インターネット経由の Arozcast 画面共有用の内蔵 TURN リレー",
+                "desc/cluster/Cluster Settings": "クラスターの作成・参加とストレージ・スケジューリングの設定",
+                "desc/cluster/Cluster Info": "このノード、ピア、レプリケーション、スケジューリングの状態",
+                "desc/cluster/Cluster Jobs": "クラスター内の任意のノードでスクリプトを実行",
+                "desc/cluster/Neighbourhood": "クラスタリング可能な近くの ArOZ ホスト",
+                "desc/ainteg/CNN Inference": "画像・顔認識用の外部 CXNNAIO 画像推論サーバーを設定",
+                "desc/desktop/Wallpaper": "デスクトップの壁紙設定",
+                "desc/desktop/Sounds": "システムサウンドの設定",
+                "desc/desktop/Theme": "システムのテーマカラー",
+                "desc/desktop/Mobile UX": "モバイルデスクトップのショートカット",
+                "desc/desktop/Startup Interface": "サインイン後に開くワークスペース",
+                "desc/desktop/Notifications": "通知の受け取り方法と配信エージェントを設定",
+                "desc/device/Client Device": "使用中のブラウザーの詳細",
+                "desc/device/Device Testing": "オーディオ、ディスプレイ、キーボード、マウス、タッチのテスト",
+                "desc/device/Language": "システムの表示言語を設定",
+                "desc/disk/Disk Space": "ディスク上のシステム記憶領域",
+                "desc/disk/Disk SMART": "ハードディスクの健全性チェック",
+                "desc/disk/RAID": "基本的な mdadm 機能を提供",
+                "desc/container/Docker Daemon": "Docker デーモンサービスの起動・停止・設定",
+                "desc/container/Docker Engine": "Docker のバージョン、デーモン状態、ディスク使用量とクリーンアップ",
+                "desc/container/Docker List": "実行中のコンテナーの概要と Docker Manager へのクイックアクセス",
+                "desc/disk/File Manager": "ゴミ箱の保持期間とサイズ",
+                "desc/info/Power": "ホストデバイスの電源状態を設定",
+                "desc/device/IoT Hub": "IoT デバイススキャナーの管理",
+                "desc/security/LDAP": "外部アカウントによるシステムへのアクセスを許可",
+                "desc/module/Module List": "現在システムに読み込まれているモジュールの一覧",
+                "desc/module/Default Module": "ファイルを開くときに使う既定のモジュール",
+                "desc/module/Subservices": "サブサービスの起動と停止",
+                "desc/module/Add & Remove Module": "システムへのモジュールのインストールと削除",
+                "desc/network/Port Forward": "UPnP によるポートフォワーディング",
+                "desc/network/Network Info": "ネットワーク情報",
+                "desc/network/Personal Page": "個人ウェブページ",
+                "desc/network/File Servers": "ネットワークファイル転送サーバー",
+                "desc/security/OAuth": "OIDC 互換の任意の ID プロバイダーでサインイン",
+                "desc/users/Permission Groups": "グループごとのアクセス権限を管理",
+                "desc/disk/Storage Quota": "ユーザーの残り容量",
+                "desc/users/Public Registry": "一般ユーザーがこのホストでアカウントを作成できるようにする",
+                "desc/cluster/Tasks Scheduler": "システムタスクと実行スケジューラー",
+                "desc/advance/Auto Login Mode": "ボットによるシステムへの自動ログインを許可",
+                "desc/advance/Disk Manager": "ローカルディスクのマウント、アンマウント、フォーマット",
+                "desc/advance/Shared Spaces": "コラボレーションスペース:ストレージ、制限、クリーンアップ",
+                "desc/info/Runtime": "実行中に起動パラメーターを変更",
+                "desc/disk/Storage Pools": "ストレージプールのマウント設定",
+                "desc/about/ArozOS": "この ArozOS について",
+                "desc/about/Open Source": "オープンソースコミュニティのライセンス",
+                "desc/about/License": "ArozOS のライセンス",
+                "desc/about/Vendor": "ベンダーからのお知らせ",
+                "desc/info/Host Info": "システム情報",
+                "desc/info/Performance": "システムの CPU とメモリ使用量",
+                "desc/info/Updates": "ArozOS のアップデートを実行",
+                "desc/advance/System Log": "ArozOS のシステムログを表示",
+                "desc/users/My Account": "アカウントとパスワードの管理",
+                "desc/users/User List": "このシステムに登録されているユーザーの一覧",
+                "desc/network/WiFi Info": "現在接続中の WiFi 情報",
+                "desc/network/WiFi Settings": "WiFi 接続の設定"
             }
         },
         "ko-kr": {
@@ -760,7 +1198,80 @@
                 "tab/about/Open Source": "오픈소스 구성요소",
                 "tab/about/License": "시스템 라이선스",
                 "tab/about/Vendor": "벤더",
-                "": ""
+                "": "",
+                "menu/group/AI Integration": "AI 통합",
+                "menu/group/Containers": "컨테이너",
+                "tab/desktop/Startup Interface": "시작 인터페이스",
+                "tab/desktop/Notifications": "알림",
+                "tab/disk/RAID": "RAID 어레이",
+                "tab/disk/File Manager": "파일 관리자",
+                "tab/network/Screen Share Relay": "화면 공유 릴레이",
+                "tab/advance/AGI Runtimes": "AGI 실행 인스턴스",
+                "tab/advance/Shared Spaces": "공유 공간",
+                "tab/ainteg/AI Model": "AI 모델",
+                "tab/ainteg/CNN Inference": "CNN 이미지 추론",
+                "tab/container/Docker Daemon": "Docker 데몬",
+                "tab/container/Docker Engine": "Docker 엔진",
+                "tab/container/Docker List": "컨테이너 목록",
+                "desc/advance/AGI Runtimes": "실행 중인 AGI 스크립트 VM 모니터링 및 강제 종료",
+                "desc/ainteg/AI Model": "OpenAI / Anthropic 호환 엔드포인트, 요금, 할당량 설정 및 토큰 사용량 확인",
+                "desc/security/Connection Log": "로그인 시도 기록",
+                "desc/security/Access Control": "특정 IP 범위의 로그인 차단 / 허용",
+                "desc/network/Screen Share Relay": "인터넷을 통한 Arozcast 화면 공유용 내장 TURN 릴레이",
+                "desc/cluster/Cluster Settings": "클러스터 생성 또는 참여 및 저장소·스케줄링 설정",
+                "desc/cluster/Cluster Info": "이 노드, 피어, 복제 및 스케줄링 상태",
+                "desc/cluster/Cluster Jobs": "클러스터의 모든 노드에서 스크립트 실행",
+                "desc/cluster/Neighbourhood": "클러스터링 가능한 주변 ArOZ 호스트",
+                "desc/ainteg/CNN Inference": "이미지·얼굴 인식용 외부 CXNNAIO 비전 추론 서버 설정",
+                "desc/desktop/Wallpaper": "바탕 화면 배경 설정",
+                "desc/desktop/Sounds": "시스템 사운드 설정",
+                "desc/desktop/Theme": "시스템 테마 색상",
+                "desc/desktop/Mobile UX": "모바일 바탕 화면 바로 가기",
+                "desc/desktop/Startup Interface": "로그인 후 열리는 작업 공간",
+                "desc/desktop/Notifications": "알림 수신 방법 선택 및 전달 에이전트 설정",
+                "desc/device/Client Device": "사용 중인 브라우저 정보",
+                "desc/device/Device Testing": "오디오, 디스플레이, 키보드, 마우스 및 터치 테스트",
+                "desc/device/Language": "시스템 표시 언어 설정",
+                "desc/disk/Disk Space": "디스크의 시스템 저장 공간",
+                "desc/disk/Disk SMART": "하드 디스크 상태 점검",
+                "desc/disk/RAID": "기본 mdadm 기능 제공",
+                "desc/container/Docker Daemon": "Docker 데몬 서비스 시작, 중지 및 설정",
+                "desc/container/Docker Engine": "Docker 버전, 데몬 상태, 디스크 사용량 및 정리",
+                "desc/container/Docker List": "실행 중인 컨테이너 개요 및 Docker Manager 바로 가기",
+                "desc/disk/File Manager": "휴지통 보관 기간 및 크기",
+                "desc/info/Power": "호스트 장치의 전원 상태 설정",
+                "desc/device/IoT Hub": "IoT 장치 스캐너 관리",
+                "desc/security/LDAP": "외부 계정의 시스템 접근 허용",
+                "desc/module/Module List": "현재 시스템에 로드된 모듈 목록",
+                "desc/module/Default Module": "파일을 열 때 사용할 기본 모듈",
+                "desc/module/Subservices": "하위 서비스 시작 및 종료",
+                "desc/module/Add & Remove Module": "시스템에 모듈 설치 및 제거",
+                "desc/network/Port Forward": "UPnP 기반 포트 포워딩",
+                "desc/network/Network Info": "네트워크 정보",
+                "desc/network/Personal Page": "개인 웹 페이지",
+                "desc/network/File Servers": "네트워크 파일 전송 서버",
+                "desc/security/OAuth": "OIDC 호환 ID 공급자로 로그인",
+                "desc/users/Permission Groups": "그룹별 접근 권한 관리",
+                "desc/disk/Storage Quota": "사용자 남은 공간",
+                "desc/users/Public Registry": "일반 사용자가 이 호스트에서 계정을 만들 수 있도록 허용",
+                "desc/cluster/Tasks Scheduler": "시스템 작업 및 실행 스케줄러",
+                "desc/advance/Auto Login Mode": "봇의 시스템 자동 로그인 허용",
+                "desc/advance/Disk Manager": "로컬 디스크 마운트, 마운트 해제 및 포맷",
+                "desc/advance/Shared Spaces": "협업 공간: 저장소, 제한 및 정리",
+                "desc/info/Runtime": "실행 중 시작 매개변수 변경",
+                "desc/disk/Storage Pools": "저장소 풀 마운트 설정",
+                "desc/about/ArozOS": "이 ArozOS 정보",
+                "desc/about/Open Source": "오픈 소스 커뮤니티 라이선스",
+                "desc/about/License": "ArozOS 라이선스",
+                "desc/about/Vendor": "공급업체 안내",
+                "desc/info/Host Info": "시스템 정보",
+                "desc/info/Performance": "시스템 CPU 및 메모리 사용량",
+                "desc/info/Updates": "ArozOS 업데이트 실행",
+                "desc/advance/System Log": "ArozOS 시스템 로그 보기",
+                "desc/users/My Account": "계정 및 비밀번호 관리",
+                "desc/users/User List": "이 시스템에 등록된 사용자 목록",
+                "desc/network/WiFi Info": "현재 연결된 WiFi 정보",
+                "desc/network/WiFi Settings": "WiFi 연결 설정"
             }
         }
     }

+ 56 - 7
src/web/SystemAO/locale/system_settings/desktop.json

@@ -32,7 +32,14 @@
                 "mux/sc3": "捷徑 3",
                 "mux/sc4": "捷徑 4",
                 "mux/save": "儲存捷徑",
-                "mux/saved": "捷徑已儲存,開啟行動介面即可查看變更"
+                "mux/saved": "捷徑已儲存,開啟行動介面即可查看變更",
+                "sif/title": "啟動介面",
+                "sif/desc": "選擇登入後開啟的工作區,此設定僅適用於此瀏覽器。",
+                "sif/ask": "每次詢問",
+                "sif/ask-desc": "登入後顯示工作區選擇畫面",
+                "sif/single": "你的帳戶只有一個工作區,登入後會直接開啟。",
+                "sif/saved": "已更新此瀏覽器的啟動介面。",
+                "sif/switch": "立即切換工作區"
             },
             "titles": {},
             "placeholder": {}
@@ -67,7 +74,14 @@
                 "mux/sc3": "捷徑 3",
                 "mux/sc4": "捷徑 4",
                 "mux/save": "儲存捷徑",
-                "mux/saved": "捷徑已儲存,開啟行動介面即可查看變更"
+                "mux/saved": "捷徑已儲存,開啟行動介面即可查看變更",
+                "sif/title": "啟動介面",
+                "sif/desc": "選擇登入後開啟的工作區,此設定僅適用於此瀏覽器。",
+                "sif/ask": "每次詢問",
+                "sif/ask-desc": "登入後顯示工作區選擇畫面",
+                "sif/single": "你的帳戶只有一個工作區,登入後會直接開啟。",
+                "sif/saved": "已更新此瀏覽器的啟動介面。",
+                "sif/switch": "立即切換工作區"
             },
             "titles": {},
             "placeholder": {}
@@ -102,7 +116,14 @@
                 "mux/sc3": "快捷方式 3",
                 "mux/sc4": "快捷方式 4",
                 "mux/save": "保存快捷方式",
-                "mux/saved": "快捷方式已保存,打开移动界面即可查看变更"
+                "mux/saved": "快捷方式已保存,打开移动界面即可查看变更",
+                "sif/title": "启动界面",
+                "sif/desc": "选择登录后打开的工作区,此设置仅适用于此浏览器。",
+                "sif/ask": "每次询问",
+                "sif/ask-desc": "登录后显示工作区选择界面",
+                "sif/single": "你的账户只有一个工作区,登录后会直接打开。",
+                "sif/saved": "已更新此浏览器的启动界面。",
+                "sif/switch": "立即切换工作区"
             },
             "titles": {},
             "placeholder": {}
@@ -137,7 +158,14 @@
                 "mux/sc3": "Shortcut 3",
                 "mux/sc4": "Shortcut 4",
                 "mux/save": "Save Shortcuts",
-                "mux/saved": "Shortcuts saved. Open the mobile interface to see the changes."
+                "mux/saved": "Shortcuts saved. Open the mobile interface to see the changes.",
+                "sif/title": "Startup Interface",
+                "sif/desc": "Choose which workspace opens after you sign in. This setting only applies to this browser.",
+                "sif/ask": "Ask me every time",
+                "sif/ask-desc": "Show the workspace selector after signing in",
+                "sif/single": "Your account has only one workspace, so it always opens after you sign in.",
+                "sif/saved": "Startup interface updated for this browser.",
+                "sif/switch": "Switch Workspace Now"
             },
             "titles": {},
             "placeholder": {}
@@ -172,7 +200,14 @@
                 "mux/sc3": "Shortcut 3",
                 "mux/sc4": "Shortcut 4",
                 "mux/save": "Save Shortcuts",
-                "mux/saved": "Shortcuts saved. Open the mobile interface to see the changes."
+                "mux/saved": "Shortcuts saved. Open the mobile interface to see the changes.",
+                "sif/title": "Startup Interface",
+                "sif/desc": "Choose which workspace opens after you sign in. This setting only applies to this browser.",
+                "sif/ask": "Ask me every time",
+                "sif/ask-desc": "Show the workspace selector after signing in",
+                "sif/single": "Your account has only one workspace, so it always opens after you sign in.",
+                "sif/saved": "Startup interface updated for this browser.",
+                "sif/switch": "Switch Workspace Now"
             },
             "titles": {},
             "placeholder": {}
@@ -207,7 +242,14 @@
                 "mux/sc3": "ショートカット 3",
                 "mux/sc4": "ショートカット 4",
                 "mux/save": "ショートカットを保存",
-                "mux/saved": "ショートカットを保存しました。モバイルインターフェースを開いて変更を確認してください"
+                "mux/saved": "ショートカットを保存しました。モバイルインターフェースを開いて変更を確認してください",
+                "sif/title": "起動インターフェース",
+                "sif/desc": "サインイン後に開くワークスペースを選択します。この設定はこのブラウザにのみ適用されます。",
+                "sif/ask": "毎回確認する",
+                "sif/ask-desc": "サインイン後にワークスペース選択画面を表示します",
+                "sif/single": "このアカウントのワークスペースは1つだけのため、サインイン後に常に開きます。",
+                "sif/saved": "このブラウザの起動インターフェースを更新しました。",
+                "sif/switch": "今すぐワークスペースを切り替える"
             },
             "titles": {},
             "placeholder": {}
@@ -242,7 +284,14 @@
                 "mux/sc3": "바로가기 3",
                 "mux/sc4": "바로가기 4",
                 "mux/save": "바로가기 저장",
-                "mux/saved": "바로가기가 저장되었습니다. 모바일 인터페이스를 열어 변경사항을 확인하세요"
+                "mux/saved": "바로가기가 저장되었습니다. 모바일 인터페이스를 열어 변경사항을 확인하세요",
+                "sif/title": "시작 인터페이스",
+                "sif/desc": "로그인 후 열릴 작업 공간을 선택합니다. 이 설정은 이 브라우저에만 적용됩니다.",
+                "sif/ask": "매번 묻기",
+                "sif/ask-desc": "로그인 후 작업 공간 선택 화면을 표시합니다",
+                "sif/single": "이 계정에는 작업 공간이 하나뿐이므로 로그인 후 항상 열립니다.",
+                "sif/saved": "이 브라우저의 시작 인터페이스가 업데이트되었습니다.",
+                "sif/switch": "지금 작업 공간 전환"
             },
             "titles": {},
             "placeholder": {}

+ 10 - 1
src/web/SystemAO/system_setting/main.js

@@ -131,7 +131,8 @@ function renderCards(subcats) {
     $grid.empty();
     subcats.forEach(function (s) {
         var name = getSubcatName(s);
-        var desc = s.Desc ? '<div class="card-desc">' + s.Desc + '</div>' : '';
+        var descText = getSubcatDesc(s);
+        var desc = descText ? '<div class="card-desc">' + descText + '</div>' : '';
         var $card = $('<div class="setting-card"></div>')
             .append('<img src="../../' + s.IconPath + '" onerror="this.src=\'img/unknown.png\'">')
             .append('<div class="card-text"><div class="card-title">' + name + '</div>' + desc + '</div>');
@@ -232,6 +233,14 @@ function getSubcatName(s) {
     );
 }
 
+function getSubcatDesc(s) {
+    if (!s.Desc) return '';
+    return applocale.getString(
+        'desc/' + (currentGroupId || '').toLowerCase() + '/' + s.Name,
+        s.Desc
+    );
+}
+
 function injectIME() {
     var container = document.getElementById('detail-inner');
     if (!container) return;

+ 10 - 5
src/web/desktop.html

@@ -2139,12 +2139,18 @@
             $("#searchBar").val("");
         }
 
+        //Interface Modules (Desktop, Dashboard, ...) are what the user boots into, not apps
+        //to launch, and modules without a StartDir can only be opened with a file
+        function isLaunchableModule(moduleInfo) {
+            return moduleInfo["StartDir"] != "" && moduleInfo["Group"] != "Interface Module";
+        }
+
         function listModulesType(groupType) {
             var listingItems = [];
             if (groupType == "All") {
                 //List all of the items
                 for (var i = 0; i < moduleInstalled.length; i++) {
-                    if (moduleInstalled[i]["StartDir"] != "") {
+                    if (isLaunchableModule(moduleInstalled[i])) {
                         listingItems.push(moduleInstalled[i]);
                     }
                 }
@@ -2152,15 +2158,14 @@
                 var excludeList = ["Media", "Office", "Download", "Files", "Internet", "System Settings", "System Tools", "Utilities"];
                 //List the Other groups
                 for (var i = 0; i < moduleInstalled.length; i++) {
-                    if (excludeList.includes(moduleInstalled[i]["Group"]) == false && moduleInstalled[i]["StartDir"] != "") {
-                        console.log(moduleInstalled[i]["Group"]);
+                    if (excludeList.includes(moduleInstalled[i]["Group"]) == false && isLaunchableModule(moduleInstalled[i])) {
                         listingItems.push(moduleInstalled[i]);
                     }
                 }
             } else {
                 //List the given group
                 for (var i = 0; i < moduleInstalled.length; i++) {
-                    if (moduleInstalled[i]["Group"] == groupType && moduleInstalled[i]["StartDir"] != "") {
+                    if (moduleInstalled[i]["Group"] == groupType && isLaunchableModule(moduleInstalled[i])) {
                         listingItems.push(moduleInstalled[i]);
                     }
                 }
@@ -2211,7 +2216,7 @@
                 //Load all search results
                 for (var i = 0; i < moduleInstalled.length; i++) {
                     var thisModule = moduleInstalled[i];
-                    if (thisModule["StartDir"] == ""){
+                    if (!isLaunchableModule(thisModule)){
                         continue;
                     }
                     var pathInfo = thisModule["StartDir"].split("/");

BIN
src/web/img/system/auth_icon.png


BIN
src/web/img/system/auth_icon_black.png


BIN
src/web/img/system/auth_icon_white.png


+ 10 - 5
src/web/mobile.html

@@ -617,15 +617,20 @@ function initModules(){
     }});
 }
 
+// Interface Modules (Desktop, Dashboard, ...) are what the user boots into, not apps to launch
+function isLaunchableModule(m){
+    return !!m.StartDir && m.Group!=="Interface Module";
+}
+
 function getOrderedModules(){
     var result = [];
     appOrder.forEach(function(n){
         var m=moduleInstalled.find(function(x){return x.Name===n;});
-        if(m) result.push(m);
+        if(m && isLaunchableModule(m)) result.push(m);
     });
     // Auto-include newly installed modules (not in appOrder and not explicitly removed)
     moduleInstalled.forEach(function(m){
-        if(m.StartDir
+        if(isLaunchableModule(m)
             && !result.find(function(x){return x.Name===m.Name;})
             && removedApps.indexOf(m.Name)===-1){
             result.push(m);
@@ -639,12 +644,12 @@ function renderGrid(filter){
     // Rebuild appOrder from active (non-removed) modules when not filtering
     if(!filter){
         appOrder = getOrderedModules()
-            .filter(function(m){return !!m.StartDir;})
+            .filter(isLaunchableModule)
             .map(function(m){return m.Name;});
     }
     var idx=0;
     getOrderedModules().forEach(function(m){
-        if(!m.StartDir) return;
+        if(!isLaunchableModule(m)) return;
         if(filter && !m.Name.toLowerCase().includes(filter.toLowerCase())) return;
         var ic = m.IconPath||"img/system/service.png";
         var name = escH(m.Name);
@@ -664,7 +669,7 @@ function renderGrid(filter){
     if(isEditMode && !filter){
         removedApps.forEach(function(name){
             var m=moduleInstalled.find(function(x){return x.Name===name;});
-            if(!m||!m.StartDir) return;
+            if(!m||!isLaunchableModule(m)) return;
             var ic = m.IconPath||"img/system/service.png";
             var attr = escA(m.Name);
             grid.append('<div class="app-item app-removed" data-mod="'+attr+'">'

+ 1 - 1
src/wifi.go

@@ -62,7 +62,7 @@ func WiFiInit() {
 			})
 			registerSetting(settingModule{
 				Name:         "WiFi Settings",
-				Desc:         "Setup WiFi Conenctions",
+				Desc:         "Set up WiFi connections",
 				IconPath:     "SystemAO/network/img/WiFi.png",
 				Group:        "Network",
 				StartDir:     "SystemAO/network/wifi.html",