Browse Source

feat: frontend i18n support

wangweimin 4 năm trước cách đây
mục cha
commit
682ae6639b

+ 5 - 4
webiojs/src/handlers/input.ts

@@ -5,6 +5,7 @@ import {state} from '../state'
 import {all_input_items} from "../models/input"
 import {all_input_items} from "../models/input"
 import {CommandHandler} from "./base"
 import {CommandHandler} from "./base"
 import {close_input, show_input} from "../ui";
 import {close_input, show_input} from "../ui";
+import {t} from "../i18n";
 
 
 /*
 /*
 * 整个输入区域的控制类
 * 整个输入区域的控制类
@@ -158,9 +159,9 @@ class FormController {
                     <form>
                     <form>
                         <div class="input-container"></div>
                         <div class="input-container"></div>
                         <div class="ws-form-submit-btns">
                         <div class="ws-form-submit-btns">
-                            <button type="submit" class="btn btn-primary">提交</button>
-                            <button type="reset" class="btn btn-warning">重置</button>
-                            {{#cancelable}}<button type="button" class="pywebio_cancel_btn btn btn-danger">取消</button>{{/cancelable}}
+                            <button type="submit" class="btn btn-primary">${t("submit")}</button>
+                            <button type="reset" class="btn btn-warning">${t("reset")}</button>
+                            {{#cancelable}}<button type="button" class="pywebio_cancel_btn btn btn-danger">${t("cancel")}</button>{{/cancelable}}
                         </div>
                         </div>
                     </form>
                     </form>
                 </div>
                 </div>
@@ -208,7 +209,7 @@ class FormController {
 
 
             for (let name in that.name2input)
             for (let name in that.name2input)
                 if (!that.name2input[name].check_valid())
                 if (!that.name2input[name].check_valid())
-                    return error_alert('输入项存在错误,请消除错误后再提交');
+                    return error_alert(t("error_in_input"));
 
 
             let data: { [i: string]: any } = {};
             let data: { [i: string]: any } = {};
             $.each(that.name2input, (name, ctrl) => {
             $.each(that.name2input, (name, ctrl) => {

+ 60 - 0
webiojs/src/i18n.ts

@@ -0,0 +1,60 @@
+// @ts-ignore
+const userLangCode: string = (navigator.language || navigator.userLanguage || 'en').toLowerCase();
+
+const userLang: string = userLangCode.split('-')[0];
+
+
+const translations: { [lang: string]: { [msgid: string]: string } } = {
+    "en": {
+        "disconnected_with_server": "Disconnected from the server, please refresh the page",
+        "connect_fail": "Failed to connect to server!",
+        "error_in_input": "There is an error with the input, please fix the error first",
+        "file_size_exceed": 'File "%1" size exceeds limit: the size of a single file must not exceed %2',
+        "file_total_size_exceed": "The total file size exceeds the limit: the total file size must not exceed %1",
+        "submit": "Submit",
+        "reset": "Reset",
+        "cancel": "Cancel",
+    },
+    "zh": {
+        "disconnected_with_server": "与服务器连接已断开,请刷新页面重新操作",
+        "connect_fail": "连接服务器失败!",
+        "error_in_input": "输入项存在错误,请消除错误后再提交",
+        "file_size_exceed": '文件"%1"大小超过限制: 单个文件大小不超过%2',
+        "file_total_size_exceed": "文件总大小超过限制: 文件总大小不超过%1",
+        "submit": "提交",
+        "reset": "重置",
+        "cancel": "取消",
+    },
+};
+
+
+// sprintf equivalent, takes a string and some arguments to make a computed string
+// eg: strfmt("%1 dogs are in %2", 7, "the kitchen"); => "7 dogs are in the kitchen"
+// eg: strfmt("I like %1, bananas and %1", "apples"); => "I like apples, bananas and apples"
+function strfmt(fmt: string) {
+    let args = arguments;
+
+    return fmt
+    // put space after double % to prevent placeholder replacement of such matches
+        .replace(/%%/g, '%% ')
+        // replace placeholders
+        .replace(/%(\d+)/g, function (str, p1) {
+            return args[p1];
+        })
+        // replace double % and space with single %
+        .replace(/%% /g, '%')
+}
+
+export function t(msgid: string, ...args:string[]): string {
+    let fmt = null;
+    for (let lang of [userLangCode, userLang, 'en']) {
+        if (translations[lang] && translations[lang][msgid]){
+            fmt = translations[lang][msgid];
+            break;
+        }
+    }
+    if (fmt === null)
+        throw Error(`No translation for "${msgid}" in "${userLangCode}"`);
+
+    return strfmt.apply(null, [fmt, ...args]);
+}

+ 3 - 2
webiojs/src/models/input/file.ts

@@ -1,6 +1,7 @@
 import {Session} from "../../session";
 import {Session} from "../../session";
 import {InputItem} from "./base";
 import {InputItem} from "./base";
 import {deep_copy} from "../../utils"
 import {deep_copy} from "../../utils"
+import {t} from "../../i18n";
 
 
 const file_input_tpl = `
 const file_input_tpl = `
 <div class="form-group">
 <div class="form-group">
@@ -60,13 +61,13 @@ export class File extends InputItem {
                     that.valid = false;
                     that.valid = false;
                     that.update_input_helper(-1, {
                     that.update_input_helper(-1, {
                         'valid_status': false,
                         'valid_status': false,
-                        'invalid_feedback': `文件"${f.name}"大小超过限制: 单个文件大小不超过${that._formate_size(that.spec.max_size)}`
+                        'invalid_feedback': t("file_size_exceed", f.name, that._formate_size(that.spec.max_size)),
                     });
                     });
                 } else if (that.spec.max_total_size && total_size > that.spec.max_total_size) {
                 } else if (that.spec.max_total_size && total_size > that.spec.max_total_size) {
                     that.valid = false;
                     that.valid = false;
                     that.update_input_helper(-1, {
                     that.update_input_helper(-1, {
                         'valid_status': false,
                         'valid_status': false,
-                        'invalid_feedback': `文件总大小超过限制: 文件总大小不超过${that._formate_size(that.spec.max_total_size)}`
+                        'invalid_feedback': t("file_total_size_exceed",that._formate_size(that.spec.max_total_size))
                     });
                     });
                     return;
                     return;
                 }
                 }

+ 4 - 3
webiojs/src/session.ts

@@ -1,5 +1,6 @@
 import {error_alert} from "./utils";
 import {error_alert} from "./utils";
 import {state} from "./state";
 import {state} from "./state";
+import {t} from "./i18n";
 
 
 export interface Command {
 export interface Command {
     command: string
     command: string
@@ -97,7 +98,7 @@ export class WebSocketSession implements Session {
 
 
     send_message(msg: ClientEvent, onprogress?: (loaded: number, total: number) => void): void {
     send_message(msg: ClientEvent, onprogress?: (loaded: number, total: number) => void): void {
         if (this.closed())
         if (this.closed())
-            return error_alert("与服务器连接已断开,请刷新页面重新操作");
+            return error_alert(t("disconnected_with_server"));
 
 
         if (this.ws === null)
         if (this.ws === null)
             return console.error('WebSocketWebIOSession.ws is null when invoke WebSocketWebIOSession.send_message. ' +
             return console.error('WebSocketWebIOSession.ws is null when invoke WebSocketWebIOSession.send_message. ' +
@@ -193,7 +194,7 @@ export class HttpSession implements Session {
 
 
     send_message(msg: ClientEvent, onprogress?: (loaded: number, total: number) => void): void {
     send_message(msg: ClientEvent, onprogress?: (loaded: number, total: number) => void): void {
         if (this.closed())
         if (this.closed())
-            return error_alert("与服务器连接已断开,请刷新页面重新操作");
+            return error_alert(t("disconnected_with_server"));
 
 
         if (this.debug) console.info('<<<', msg);
         if (this.debug) console.info('<<<', msg);
         $.ajax({
         $.ajax({
@@ -216,7 +217,7 @@ export class HttpSession implements Session {
             },
             },
             error: function () {  // todo
             error: function () {  // todo
                 console.error('Http push event failed, event data: %s', msg);
                 console.error('Http push event failed, event data: %s', msg);
-                error_alert("连接服务器失败!");
+                error_alert(t("connect_fail"));
             }
             }
         });
         });