diff --git a/spx-gui/src/components/project/ProjectCreate.vue b/spx-gui/src/components/project/ProjectCreate.vue
index 155d36f1d..c1e332a57 100644
--- a/spx-gui/src/components/project/ProjectCreate.vue
+++ b/spx-gui/src/components/project/ProjectCreate.vue
@@ -4,10 +4,10 @@
-
+
{{ _t({ en: 'Cancel', zh: '取消' }) }}
-
+
{{ _t({ en: 'Create', zh: '创建' }) }}
@@ -17,9 +17,9 @@
-../project
\ No newline at end of file
diff --git a/spx-gui/src/utils/exception.ts b/spx-gui/src/utils/exception.ts
index 795a1dc5b..16808b9ea 100644
--- a/spx-gui/src/utils/exception.ts
+++ b/spx-gui/src/utils/exception.ts
@@ -4,7 +4,7 @@
import { useMessage } from 'naive-ui'
import { useI18n } from './i18n'
-import type { LocaleMessage, FunctionLocaleMessage } from './i18n'
+import type { LocaleMessage } from './i18n'
/**
* Exceptions are like errors, while slightly different:
@@ -28,6 +28,11 @@ export class DefaultException extends Exception {
}
}
+/**
+ * Cancelled is a special exception, it stands for a "cancel operation" because of user ineraction.
+ * Like other exceptions, it breaks normal flows, while it is supposed to be ignored by all user-feedback components,
+ * so the user will not be notified of cancelled exceptions.
+ */
export class Cancelled extends Exception {
name = 'Cancelled'
userMessage = null
@@ -36,43 +41,41 @@ export class Cancelled extends Exception {
}
}
-export function cancel(): never {
- throw new Cancelled()
-}
-
-const failedMessage: FunctionLocaleMessage<[summary: string, reason: string | null]> = {
- en: (summary, reason) => (reason ? `${summary} (${reason})` : summary),
- zh: (summary, reason) => (reason ? `${summary}(${reason})` : summary)
-}
+const failedMessage = (summary: string, reason: string | null) => ({
+ en: reason ? `${summary} (${reason})` : summary,
+ zh: reason ? `${summary}(${reason})` : summary
+})
-export function useMessageHandle Promise>(
- action: F,
+export function useMessageHandle(
+ action: (...args: Args) => Promise,
failureSummaryMessage: LocaleMessage,
- successMessage?: LocaleMessage
-): F {
+ successMessage?: LocaleMessage | ((ret: Ret) => LocaleMessage)
+): (...args: Args) => Promise {
const m = useMessage()
const { t } = useI18n()
- return (() => {
- return action().then(
+ return ((...args: Args) => {
+ return action(...args).then(
(ret) => {
if (successMessage != null) {
- m.success(() => t(successMessage))
+ const successText = t(typeof successMessage === 'function' ? successMessage(ret) : successMessage)
+ m.success(() => successText)
}
return ret
},
(e) => {
- if (e instanceof Cancelled) return
- let reasonMessage: LocaleMessage | null = null
- if (e instanceof Exception && e.userMessage != null) {
- reasonMessage = e.userMessage
+ if (!(e instanceof Cancelled)) {
+ let reasonMessage: LocaleMessage | null = null
+ if (e instanceof Exception && e.userMessage != null) {
+ reasonMessage = e.userMessage
+ }
+ const result = t(failedMessage(t(failureSummaryMessage), t(reasonMessage)))
+ m.error(() => result)
}
- const result = t(failedMessage, t(failureSummaryMessage), t(reasonMessage))
- m.error(() => result)
throw e
}
)
- }) as F
+ })
}
// TODO: helpers for in-place feedback
diff --git a/spx-gui/src/utils/i18n/README.md b/spx-gui/src/utils/i18n/README.md
index a3ba3833a..0a732eb5e 100644
--- a/spx-gui/src/utils/i18n/README.md
+++ b/spx-gui/src/utils/i18n/README.md
@@ -41,17 +41,17 @@ const { t } = useI18n()
const signoutText = t({ en: 'Sign out', zh: '登出' })
```
-### Function Locale Message
+### Locale Message Functions
-Function-locale-messages are messages that extra information are needed when translating. For example:
+Locale-message-functions are functions that return locale message. It is useful when extra information is needed when constructing locale messages. For example:
```ts
-const projectSummaryMessage: FunctionLocaleMessage<[num: number]> = {
- en: num => `You have ${num} project${num > 1 ? 's' : ''}`,
- zh: num => `你有 ${num} 个项目`
-}
+const projectSummaryMessage = (num: number) => ({
+ en: `You have ${num} project${num > 1 ? 's' : ''}`,
+ zh: `你有 ${num} 个项目`
+})
-const projectSummary = t(projectSummaryMessage, 3) // "You have 3 projects" / "你有 3 个项目"
+const projectSummary = t(projectSummaryMessage(3)) // "You have 3 projects" / "你有 3 个项目"
```
It's like [interpolations](https://vue-i18n.intlify.dev/guide/essentials/syntax.html#interpolations) in vue-i18n, but simpler & more powerful.
@@ -75,15 +75,3 @@ const helloMessage = {
const resultMessage = mapMessage(helloMessage, hello => hello + ' foo')
console.log(t(resultMessage)) // "Hello foo" / "你好 foo"
```
-
-We can also use `mapMessage` with function-locale-messages:
-
-```ts
-const projectSummaryMessage: FunctionLocaleMessage<[num: number]> = {
- en: num => `You have ${num} project${num > 1 ? 's' : ''}`,
- zh: num => `你有 ${num} 个项目`
-}
-
-const resultMessage = mapMessage(projectSummaryMessage, f => f(3))
-console.log(t(resultMessage)) // "You have 3 projects" / "你有 3 个项目"
-```
\ No newline at end of file
diff --git a/spx-gui/src/utils/i18n/index.ts b/spx-gui/src/utils/i18n/index.ts
index caf6848c2..d009a390f 100644
--- a/spx-gui/src/utils/i18n/index.ts
+++ b/spx-gui/src/utils/i18n/index.ts
@@ -11,8 +11,6 @@ export type Translated = string
export type LocaleMessage = Record
-export type FunctionLocaleMessage = Record Translated>
-
export interface I18nConfig {
/** Initial lang */
lang: Lang
@@ -43,17 +41,9 @@ export class I18n implements ObjectPlugin<[]> {
/** Translate */
t(message: LocaleMessage): Translated
t(message: LocaleMessage | null): Translated | null
- t(message: FunctionLocaleMessage, ...args: Args): Translated
- t(
- message: FunctionLocaleMessage | null,
- ...args: Args
- ): Translated | null
- t(message: LocaleMessage | FunctionLocaleMessage | null, ...args: unknown[]) {
+ t(message: LocaleMessage | null) {
if (message == null) return null
const val = message[this.lang.value]
- if (typeof val === 'function') {
- return (val as any)(...args)
- }
return val
}
@@ -74,7 +64,7 @@ export function useI18n() {
return i18n
}
-export function mapMessage, T>(
+export function mapMessage(
message: M,
process: (value: M[keyof M], lang: Lang) => T
): Record {