Browse Source

update i18n

SyuanYu 2 years ago
parent
commit
d01d93e0cd

+ 1 - 1
frontend/src/api.ts

@@ -47,7 +47,7 @@ export const api = {
     });
   },
   async registerUser(data: IUserProfileCreate) {
-    return axios.post(`${apiUrl}/api/v1/users/register`, data);
+    return axios.post(`${apiUrl}/api/v1/users/open`, data);
   },
   async testCeleryMsg(token: string, data:{msg: string}){
     return axios.post<{msg:string}>(`${apiUrl}/api/v1/utils/test-celery/msg`, data, authHeaders(token));

+ 2 - 2
frontend/src/components/Navbar.vue

@@ -4,7 +4,7 @@ import { useI18n } from "vue-i18n";
 
 const { t, locale } = useI18n();
 
-let items = reactive([
+let lang = reactive([
   { title: "English", text: "en" },
   { title: "中文", text: "zh" },
 ]);
@@ -56,7 +56,7 @@ function setLang(lang: String) {
         </template>
         <v-list>
           <v-list-item
-            v-for="(item, index) in items"
+            v-for="(item, index) in lang"
             :key="index"
             :value="item.text"
             @click="setLang(item.text)"

+ 12 - 2
frontend/src/language/en.json

@@ -1,8 +1,9 @@
 {
     "login" : "Login",
     "loginLink" : "Login",
-    "userProfile": "User Profile",
     "logout": "Logout",
+    "submit": "Submit",
+    "cancel": "Cancel",
     "userName": "User name",
     "password": "Password",
     "emailAddress": "Email Address",
@@ -17,6 +18,15 @@
     "privacy_term_1": "Registeration implies acception of \n \n \n",
     "privacy_term_2": "terms of service and privacy policy",
     "forgotPsd": "Forgot Password",
+    "passwordRecovery": "Password Recovery",
     "describe_1": "Make your first video for promotion, creation and life today",
-    "describe_2": "Let's get started with AI Presentors"
+    "describe_2": "Let's get started with AI Presentors",
+    "dashboard": "Dashboard",
+    "makeVideo": "Make Video",
+    "progress": "Progress",
+    "userProfile": "User Profile",
+    "editProfile": "Edit Profile",
+    "changePassword": "Change Password",
+    "collapse": "Collapse",
+    "language": "Language"
 }

+ 12 - 2
frontend/src/language/zh.json

@@ -1,8 +1,9 @@
 {
     "login" : "登入",
     "loginLink" : "立即登入",
-    "userProfile": "會員資料",
     "logout": "登出",
+    "submit": "送出",
+    "cancel": "取消",
     "userName": "使用者名稱",
     "password": "密碼",
     "emailAddress": "電子信箱",
@@ -17,6 +18,15 @@
     "privacy_term_1": "註冊即表示您已閱讀並同意",
     "privacy_term_2": "服務條款及隱私權政策",
     "forgotPsd": "忘記密碼",
+    "passwordRecovery": "忘記您的密碼嗎?",
     "describe_1": "將您的生活、創作、宣傳做成影片",
-    "describe_2": "開始使用 AI Presentors"
+    "describe_2": "開始使用 AI Presentors",
+    "dashboard": "首頁",
+    "makeVideo": "製作影片",
+    "progress": "影片清單",
+    "userProfile": "會員資料",
+    "editProfile": "編輯資料",
+    "changePassword": "變更密碼",
+    "collapse": "收合",
+    "language": "語言"
 }

+ 61 - 47
frontend/src/views/PasswordRecovery.vue

@@ -1,61 +1,75 @@
-<template>
-    <v-container fluid class="d-flex fill-height">
-      <v-row align="center" justify="center">
-        <v-col :cols="width">
-          <v-card class="elevation-12">
-            <v-toolbar dark color="primary">
-              <v-toolbar-title>{{appName}} - Password Recovery</v-toolbar-title>
-            </v-toolbar>
-            <v-card-text>
-              <p class="subheading">A password recovery email will be sent to the registered account</p>
-              <v-form @keyup.enter="submit" v-model="valid" ref="form" @submit.prevent="" lazy-validation>
-                <v-text-field @keyup.enter="submit" label="Username" type="text" prepend-icon="person" v-model="username" :rules="nameRules" required></v-text-field>
-              </v-form>
-            </v-card-text>
-            <v-card-actions>
-              <v-spacer></v-spacer>
-              <v-btn @click="cancel">Cancel</v-btn>
-              <v-btn @click.prevent="submit" :disabled="!valid">
-                Recover Password
-              </v-btn>
-            </v-card-actions>
-          </v-card>
-        </v-col>
-      </v-row>
-    </v-container>
-</template>
-
 <script setup lang="ts">
-import { appName } from '@/env';
-import { useMainStore } from '@/stores/main';
-import { ref, computed } from 'vue';
-import { nameRules } from '@/utils';
-import  router  from '@/router'
-import { useDisplay } from 'vuetify';
+import router from "@/router";
+import { useMainStore } from "@/stores/main";
+import { ref, computed } from "vue";
+import { required } from "@/utils";
+import { useDisplay } from "vuetify";
+import { useI18n } from "vue-i18n";
+import Navbar from "@/components/Navbar.vue";
 
+let email = ref("");
 const valid = ref(true);
-const username = ref('');
 
+const { t } = useI18n();
 const mainStore = useMainStore();
-
 const { name } = useDisplay();
 const width = computed(() => {
-        // name is reactive and
-        // must use .value
-        switch (name.value) {
-          case 'xs': return 12
-          case 'sm': return 8
-          case 'md': return 4
-        }
-
-        return 4
-      })
+  switch (name.value) {
+    case "xs":
+      return 12;
+  }
+  return 8;
+});
 
 function cancel() {
   router.back();
 }
 
 function submit() {
-  mainStore.passwordRecovery({username: username.value});
+  mainStore.passwordRecovery(email.value);
 }
-</script>
+</script>
+
+<template>
+  <Navbar />
+  <v-container class="d-flex fill-height">
+    <v-row align="center" justify="center">
+      <v-col :cols="width">
+        <v-card class="elevation-12">
+          <v-toolbar dark color="primary">
+            <v-toolbar-title>{{ t("passwordRecovery") }}</v-toolbar-title>
+          </v-toolbar>
+          <v-card-text>
+            <p class="subheading mb-3">
+              A password recovery email will be sent to the registered account
+            </p>
+            <v-form
+              @keyup.enter="submit"
+              v-model="valid"
+              ref="form"
+              @submit.prevent=""
+              lazy-validation
+            >
+              <v-text-field
+                @keyup.enter="submit"
+                :label="$t('emailAddress')"
+                type="text"
+                prepend-icon="email"
+                v-model="email"
+                :rules="required"
+                required
+              ></v-text-field>
+            </v-form>
+          </v-card-text>
+          <v-card-actions>
+            <v-spacer></v-spacer>
+            <v-btn @click="cancel">{{ t("cancel") }}</v-btn>
+            <v-btn @click.prevent="submit" :disabled="!valid">
+              {{ t("submit") }}
+            </v-btn>
+          </v-card-actions>
+        </v-card>
+      </v-col>
+    </v-row>
+  </v-container>
+</template>

+ 3 - 2
frontend/src/views/Signup.vue

@@ -19,6 +19,7 @@ const confirmPassword = ref("");
 let data = reactive({
   email: "",
   password: "",
+  full_name: ""
 });
 let dialog = ref(false);
 let confirmState = ref(false);
@@ -73,12 +74,12 @@ async function submit() {
           <span></span>
         </div>
         <v-form ref="form" class="login-form" lazy-validation>
-          <!-- <v-text-field
+          <v-text-field
             v-model="data.full_name"
             :rules="[(v) => !!v || '請輸入您的帳號']"
             label="使用者名稱"
             required
-          ></v-text-field> -->
+          ></v-text-field>
 
           <v-text-field
             v-model="data.email"

+ 25 - 19
frontend/src/views/main/Dashboard.vue

@@ -1,3 +1,23 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+import { useMainStore } from '@/stores/main';
+import { storeToRefs } from 'pinia';
+
+const mainStore = useMainStore();
+const mainStoreRef = storeToRefs(mainStore);
+
+const greetedUser = computed(() => {
+  const userProfile = mainStoreRef.readUserProfile;
+  if (userProfile.value) {
+    if (userProfile.value!.full_name){
+      return userProfile.value!.full_name;
+    } else {
+      return userProfile.value.email;
+    }
+  }
+});
+</script>
+
 <template>
   <v-container fluid>
     <v-card class="ma-3 pa-3">
@@ -16,22 +36,8 @@
   </v-container>
 </template>
 
-<script setup lang="ts">
-  import { computed } from 'vue';
-  import { useMainStore } from '@/stores/main';
-  import { storeToRefs } from 'pinia';
-
-  const mainStore = useMainStore();
-  const mainStoreRef = storeToRefs(mainStore);
-
-  const greetedUser = computed(() => {
-    const userProfile = mainStoreRef.readUserProfile;
-    if (userProfile.value) {
-      if (userProfile.value!.full_name){
-        return userProfile.value!.full_name;
-      } else {
-        return userProfile.value.email;
-      }
-    }
-  });
-</script>
+<style lang="scss" scoped>
+.v-toolbar__content {
+  background-image: linear-gradient(-225deg, rgb(234, 84, 19) 35%, rgb(178, 69, 146) 100%);
+}
+</style>

+ 146 - 93
frontend/src/views/main/Main.vue

@@ -1,41 +1,118 @@
+<script setup lang="ts">
+import { appName } from "@/env";
+import { reactive } from "vue";
+import type { RouteLocationNormalized, NavigationGuardNext } from "vue-router";
+import { onBeforeRouteUpdate } from "vue-router";
+import { useMainStore } from "@/stores/main";
+import { storeToRefs } from "pinia";
+import { useI18n } from "vue-i18n";
+
+
+
+    const { t, locale } = useI18n();
+    const mainStore = useMainStore();
+    const mainStoreRef = storeToRefs(mainStore);
+
+    const hasAdminAccess = mainStoreRef.readhasAdminAccess;
+
+    const miniDrawer = mainStoreRef.readDashboardMiniDrawer;
+    const showDrawer = mainStoreRef.readDashboardShowDrawer;
+
+    function switchMiniDrawer() {
+      mainStore.setDashboardMiniDrawer(
+        !mainStoreRef.readDashboardMiniDrawer.value
+      );
+    }
+
+    function switchShowDrawer() {
+      mainStore.setDashboardShowDrawer(
+        !mainStoreRef.readDashboardShowDrawer.value
+      );
+    }
+
+    function logout() {
+      mainStore.logOut();
+    }
+
+    onBeforeRouteUpdate((to, from, next) => {
+      routeGuardMain(to, from, next);
+    });
+
+    const lang = reactive([
+  { title: "English", text: "en" },
+  { title: "中文", text: "zh" },
+]);
+
+function setLang(lang: String) {
+  locale.value = `${lang}`;
+  localStorage.setItem("lang", `${lang}`);
+}
+
+    
+  
+  // beforeRouteEnter((to, from, next) =>{
+  //   routeGuardMain(to, from, next);
+  // })
+
+const routeGuardMain = async (
+  to: RouteLocationNormalized,
+  from: RouteLocationNormalized,
+  next: NavigationGuardNext
+) => {
+  if (to.path === "/main") {
+    next("/main/dashboard");
+  } else {
+    next();
+  }
+};
+</script>
+
 <template>
   <div>
-    <v-navigation-drawer persistent :rail="miniDrawer" v-model="showDrawer" >
-      <v-sheet  class="d-flex flex-column fill-height">
+    <v-navigation-drawer persistent :rail="miniDrawer" v-model="showDrawer">
+      <v-sheet class="d-flex flex-column fill-height">
         <v-sheet class="">
           <v-list>
-            <v-list-subheader><span v-show="!miniDrawer">Main menu</span></v-list-subheader>
+            <!-- <v-list-subheader><span v-show="!miniDrawer">Main menu</span></v-list-subheader> -->
             <v-list-item to="/main/dashboard" prepend-icon="dashboard">
-              <v-list-item-title>Dashboard</v-list-item-title>
+              <v-list-item-title>{{ t("dashboard") }}</v-list-item-title>
             </v-list-item>
             <v-list-item to="/main/make-video" prepend-icon="video_call">
-              <v-list-item-title>Make Video</v-list-item-title>
+              <v-list-item-title>{{ t("makeVideo") }}</v-list-item-title>
             </v-list-item>
             <v-list-item to="/main/progress" prepend-icon="list">
-              <v-list-item-title>Progress</v-list-item-title>
+              <v-list-item-title>{{ t("progress") }}</v-list-item-title>
             </v-list-item>
             <v-list-item to="/main/profile/view" prepend-icon="person">
-              <v-list-item-title>Profile</v-list-item-title>
+              <v-list-item-title>{{ t("userProfile") }}</v-list-item-title>
             </v-list-item>
             <v-list-item to="/main/profile/edit" prepend-icon="edit">
-              <v-list-item-title>Edit Profile</v-list-item-title>
+              <v-list-item-title>{{ t("editProfile") }}</v-list-item-title>
             </v-list-item>
             <v-list-item to="/main/profile/password" prepend-icon="key">
-              <v-list-item-title>Change Password</v-list-item-title>
+              <v-list-item-title>{{ t("changePassword") }}</v-list-item-title>
             </v-list-item>
           </v-list>
         </v-sheet>
         <v-divider></v-divider>
         <v-sheet class="">
           <v-list subheader v-show="hasAdminAccess">
-            <v-list-subheader><span v-show="!miniDrawer">Admin</span></v-list-subheader>
+            <v-list-subheader
+              ><span v-show="!miniDrawer">Admin</span></v-list-subheader
+            >
             <v-list-item to="/main/admin/users/all" prepend-icon="people">
               <v-list-item-title>Manage Users</v-list-item-title>
             </v-list-item>
-            <v-list-item to="/main/admin/users/create" prepend-icon="person_add">
+            <v-list-item
+              to="/main/admin/users/create"
+              prepend-icon="person_add"
+            >
               <v-list-item-title>Create User</v-list-item-title>
             </v-list-item>
-            <v-list-item to="/main/admin/test-celery" prepend-icon="engineering">
+            <v-list-item
+              to="/main/admin/test-celery"
+              prepend-icon="engineering"
+            >
               <v-list-item-title>Test Celery</v-list-item-title>
             </v-list-item>
           </v-list>
@@ -44,100 +121,76 @@
         <v-sheet class="mt-auto">
           <v-list>
             <v-list-item @click="logout" prepend-icon="logout">
-                <v-list-item-title>Logout</v-list-item-title>
-              </v-list-item>
+              <v-list-item-title>{{ t("logout") }}</v-list-item-title>
+            </v-list-item>
             <v-divider></v-divider>
-            <v-list-item @click="switchMiniDrawer" :prepend-icon="miniDrawer ? 'chevron_right' : 'chevron_left'">
-                <v-list-item-title>Collapse</v-list-item-title>
+            <v-list-item
+              @click="switchMiniDrawer"
+              :prepend-icon="miniDrawer ? 'chevron_right' : 'chevron_left'"
+            >
+              <v-list-item-title>{{ t("collapse") }}</v-list-item-title>
             </v-list-item>
           </v-list>
         </v-sheet>
       </v-sheet>
     </v-navigation-drawer>
     <v-main>
-    <v-toolbar dark color="primary" >
-      <v-app-bar-nav-icon @click.stop="switchShowDrawer"></v-app-bar-nav-icon>
-      <v-toolbar-title v-text="appName"></v-toolbar-title>
-      <v-spacer></v-spacer>
-      <v-menu bottom left offset-y>
-        <template v-slot:activator="{ props }">
-          <v-btn icon="more_vert" v-bind="props"/>
-        </template>
-        <v-list>
-          <v-list-item to="/main/profile" append-icon="person">
-              <v-list-item-title>Profile</v-list-item-title>
-          </v-list-item>
-          <v-list-item @click="logout" append-icon="logout">
-            <v-list-item-title>Logout</v-list-item-title>
+      <v-toolbar class="navbar">
+        <v-app-bar-nav-icon @click.stop="switchShowDrawer"></v-app-bar-nav-icon>
+        <v-toolbar-title v-text="appName"></v-toolbar-title>
+        <v-spacer></v-spacer>
+        <v-menu bottom left offset-y :close-on-content-click="false">
+          <template v-slot:activator="{ props }">
+            <v-btn icon="more_vert" v-bind="props" />
+          </template>
+          <v-list>
+            <v-list-item to="/main/profile" append-icon="person">
+              <v-list-item-title>{{ t("userProfile") }}</v-list-item-title>
+            </v-list-item>
+            <!-- <v-list-item to="/main/profile" append-icon="language">
+              <v-list-item-title>{{ t("language") }}</v-list-item-title>
+            </v-list-item> -->
 
+            <v-list-group value="Admin">
+              <template v-slot:activator="{ props }">
+                <v-list-item v-bind="props">
+                  <v-list-item-title>{{ t("language") }}</v-list-item-title>
+                </v-list-item>
+              </template>
+
+              <v-list-item
+            v-for="(item, index) in lang"
+            :key="index"
+            :value="item.text"
+            @click="setLang(item.text)"
+          >
+            <v-list-item-title>{{ item.title }}</v-list-item-title>
           </v-list-item>
-        </v-list>
-      </v-menu>
-    </v-toolbar>
+            </v-list-group>
+
+            <v-list-item @click="logout" append-icon="logout">
+              <v-list-item-title>{{ t("logout") }}</v-list-item-title>
+            </v-list-item>
+          </v-list>
+        </v-menu>
+      </v-toolbar>
       <router-view></router-view>
-  </v-main>
-    
+    </v-main>
+
     <v-footer class="pa-3" app>
       <v-spacer></v-spacer>
-      <span>&copy; {{appName}}</span>
+      <span>&copy; {{ appName }}</span>
     </v-footer>
   </div>
 </template>
 
-<script lang="ts">
-import { appName } from '@/env';
-import type { RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
-import { onBeforeRouteUpdate } from 'vue-router';
-import { useMainStore } from '@/stores/main';
-import { storeToRefs } from "pinia";
-
-
-export default{
-  setup(){
-    const mainStore = useMainStore();
-    const mainStoreRef = storeToRefs(mainStore);
-
-    const hasAdminAccess = mainStoreRef.readhasAdminAccess;
-
-    const miniDrawer = mainStoreRef.readDashboardMiniDrawer;
-    const showDrawer = mainStoreRef.readDashboardShowDrawer;
-
-    function switchMiniDrawer() {
-      mainStore.setDashboardMiniDrawer( !mainStoreRef.readDashboardMiniDrawer.value );
-    }
-
-    function switchShowDrawer() {
-      mainStore.setDashboardShowDrawer( !mainStoreRef.readDashboardShowDrawer.value );
-    }
-    
-    function logout(){
-      mainStore.logOut();
-    }
-
-    onBeforeRouteUpdate((to, from, next) =>  {
-      routeGuardMain(to, from, next);
-    });
-
-    return {
-      appName,
-      hasAdminAccess,
-      miniDrawer,
-      showDrawer,
-      switchMiniDrawer,
-      switchShowDrawer,
-      logout,
-    }
-  },
-  beforeRouteEnter(to, from, next){
-    routeGuardMain(to, from, next);
-  }
-};
-const routeGuardMain = async (to:RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
-  if (to.path === '/main') {
-    next('/main/dashboard');
-  } else {
-    next();
-  }
-};
-
-</script>
+<style lang="scss" scoped>
+.navbar {
+  color: #fff;
+  background-image: linear-gradient(
+    -225deg,
+    rgb(234, 84, 19) 35%,
+    rgb(178, 69, 146) 100%
+  );
+}
+</style>

+ 1 - 2
frontend/src/views/main/Start.vue

@@ -25,7 +25,6 @@
   
   //lifecycle
   
-
   //function
   const startRouteGuard = async (to:RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
     const mainStore = useMainStore();
@@ -33,7 +32,7 @@
     mainStore.checkLoggedIn();
     if (mainStoreRef.readIsLoggedIn.value) {
       if (to.path === '/login' || to.path === '/') {
-        next('/main');
+        next('/main/dashboard');
       } else {
         next();
       }