@rimori/client 1.4.4 → 1.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -0
- package/dist/cli/scripts/release/detect-translation-languages.d.ts +5 -0
- package/dist/cli/scripts/release/detect-translation-languages.js +43 -0
- package/dist/cli/scripts/release/release-config-upload.js +4 -0
- package/dist/cli/scripts/release/release-translation-upload.d.ts +6 -0
- package/dist/cli/scripts/release/release-translation-upload.js +87 -0
- package/dist/cli/scripts/release/release.d.ts +1 -1
- package/dist/cli/scripts/release/release.js +14 -5
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +2 -2
- package/dist/core/controller/EnhancedUserInfo.d.ts +0 -0
- package/dist/core/controller/EnhancedUserInfo.js +1 -0
- package/dist/core/controller/SettingsController.d.ts +7 -1
- package/dist/core/core.d.ts +1 -2
- package/dist/core/core.js +0 -1
- package/dist/fromRimori/EventBus.js +23 -23
- package/dist/fromRimori/PluginTypes.d.ts +4 -4
- package/dist/hooks/I18nHooks.d.ts +11 -0
- package/dist/hooks/I18nHooks.js +25 -0
- package/dist/i18n/I18nHooks.d.ts +11 -0
- package/dist/i18n/I18nHooks.js +25 -0
- package/dist/i18n/Translator.d.ts +43 -0
- package/dist/i18n/Translator.js +118 -0
- package/dist/i18n/config.d.ts +7 -0
- package/dist/i18n/config.js +20 -0
- package/dist/i18n/createI18nInstance.d.ts +7 -0
- package/dist/i18n/createI18nInstance.js +31 -0
- package/dist/i18n/hooks.d.ts +11 -0
- package/dist/i18n/hooks.js +25 -0
- package/dist/i18n/index.d.ts +4 -0
- package/dist/i18n/index.js +4 -0
- package/dist/i18n/types.d.ts +7 -0
- package/dist/i18n/types.js +1 -0
- package/dist/i18n/useRimoriI18n.d.ts +11 -0
- package/dist/i18n/useRimoriI18n.js +41 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin/RimoriClient.d.ts +3 -0
- package/dist/plugin/RimoriClient.js +6 -0
- package/dist/plugin/TranslationController.d.ts +38 -0
- package/dist/plugin/TranslationController.js +105 -0
- package/dist/plugin/Translator.d.ts +38 -0
- package/dist/plugin/Translator.js +101 -0
- package/dist/utils/LanguageClass.d.ts +36 -0
- package/dist/utils/LanguageClass.example.d.ts +0 -0
- package/dist/utils/LanguageClass.example.js +1 -0
- package/dist/utils/LanguageClass.js +50 -0
- package/dist/utils/LanguageClass.test.d.ts +0 -0
- package/dist/utils/LanguageClass.test.js +1 -0
- package/package.json +12 -14
- package/prettier.config.js +1 -1
- package/src/cli/scripts/release/detect-translation-languages.ts +37 -0
- package/src/cli/scripts/release/release-config-upload.ts +5 -0
- package/src/cli/scripts/release/release.ts +20 -4
- package/src/cli/types/DatabaseTypes.ts +10 -2
- package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +2 -2
- package/src/core/controller/SettingsController.ts +8 -1
- package/src/core/core.ts +1 -2
- package/src/fromRimori/EventBus.ts +47 -76
- package/src/fromRimori/PluginTypes.ts +17 -26
- package/src/hooks/I18nHooks.ts +33 -0
- package/src/index.ts +1 -1
- package/src/plugin/RimoriClient.ts +9 -1
- package/src/plugin/TranslationController.ts +105 -0
- package/src/utils/Language.ts +0 -72
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useRimori } from '../providers/PluginProvider';
|
|
3
|
+
/**
|
|
4
|
+
* Custom useTranslation hook that provides a translation function and indicates readiness
|
|
5
|
+
* @returns An object containing the translation function (`t`) and a boolean (`ready`) indicating if the translator is initialized.
|
|
6
|
+
*/
|
|
7
|
+
export function useTranslation() {
|
|
8
|
+
const { plugin } = useRimori();
|
|
9
|
+
const [translatorInstance, setTranslatorInstance] = useState(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
void plugin.getTranslator().then(setTranslatorInstance);
|
|
12
|
+
}, [plugin]);
|
|
13
|
+
const safeT = (key, options) => {
|
|
14
|
+
if (!translatorInstance)
|
|
15
|
+
return '\u200B'; // zero-width space
|
|
16
|
+
try {
|
|
17
|
+
return translatorInstance.t(key, options);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error('Translation error:', error);
|
|
21
|
+
return key;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return { t: safeT, ready: translatorInstance !== null };
|
|
25
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ThirdPartyModule, TOptions } from 'i18next';
|
|
2
|
+
/**
|
|
3
|
+
* Translator class for handling internationalization
|
|
4
|
+
*/
|
|
5
|
+
export declare class Translator {
|
|
6
|
+
private currentLanguage;
|
|
7
|
+
private isInitialized;
|
|
8
|
+
private i18n;
|
|
9
|
+
constructor(initialLanguage: string);
|
|
10
|
+
/**
|
|
11
|
+
* Initialize translator with user's language
|
|
12
|
+
* @param userLanguage - Language code from user info
|
|
13
|
+
*/
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
private getTranslationUrl;
|
|
16
|
+
/**
|
|
17
|
+
* Initialize i18n with or without React support
|
|
18
|
+
* @param isReact - Whether to use React-specific features
|
|
19
|
+
*/
|
|
20
|
+
private getI18n;
|
|
21
|
+
usePlugin(plugin: ThirdPartyModule): void;
|
|
22
|
+
/**
|
|
23
|
+
* Fetch translations manually from the current domain
|
|
24
|
+
* @param language - Language code to fetch
|
|
25
|
+
* @returns Promise with translation data
|
|
26
|
+
*/
|
|
27
|
+
private fetchTranslations;
|
|
28
|
+
/**
|
|
29
|
+
* Get translation for a key
|
|
30
|
+
* @param key - Translation key
|
|
31
|
+
* @param options - Translation options
|
|
32
|
+
* @returns Translated string
|
|
33
|
+
*/
|
|
34
|
+
t(key: string, options?: TOptions): string;
|
|
35
|
+
/**
|
|
36
|
+
* Get current language
|
|
37
|
+
*/
|
|
38
|
+
getCurrentLanguage(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Check if translator is initialized
|
|
41
|
+
*/
|
|
42
|
+
isReady(): boolean;
|
|
43
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import i18n from './config';
|
|
11
|
+
import { createInstance } from 'i18next';
|
|
12
|
+
/**
|
|
13
|
+
* Translator class for handling internationalization
|
|
14
|
+
*/
|
|
15
|
+
export class Translator {
|
|
16
|
+
constructor(initialLanguage) {
|
|
17
|
+
this.currentLanguage = initialLanguage;
|
|
18
|
+
this.isInitialized = false;
|
|
19
|
+
this.i18n = this.getI18n();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Initialize translator with user's language
|
|
23
|
+
* @param userLanguage - Language code from user info
|
|
24
|
+
*/
|
|
25
|
+
initialize() {
|
|
26
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
if (this.isInitialized) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
// Fetch translations manually
|
|
32
|
+
const translations = yield this.fetchTranslations(this.currentLanguage);
|
|
33
|
+
// Add translations to i18n
|
|
34
|
+
i18n.addResourceBundle(this.currentLanguage, 'translation', translations);
|
|
35
|
+
// Change language
|
|
36
|
+
yield i18n.changeLanguage(this.currentLanguage);
|
|
37
|
+
this.isInitialized = true;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.warn('Failed to initialize translator:', error);
|
|
41
|
+
// Ensure we have at least English fallback
|
|
42
|
+
if (!this.isInitialized) {
|
|
43
|
+
this.currentLanguage = 'en';
|
|
44
|
+
yield this.initialize();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
getTranslationUrl(language) {
|
|
50
|
+
return `${window.location.origin}/locales/${language}/translation.json`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Initialize i18n with or without React support
|
|
54
|
+
* @param isReact - Whether to use React-specific features
|
|
55
|
+
*/
|
|
56
|
+
getI18n(isReact = false) {
|
|
57
|
+
return createInstance({
|
|
58
|
+
fallbackLng: 'en',
|
|
59
|
+
debug: window.location.hostname === 'localhost',
|
|
60
|
+
interpolation: {
|
|
61
|
+
escapeValue: !isReact,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
usePlugin(plugin) {
|
|
66
|
+
this.i18n.use(plugin);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Fetch translations manually from the current domain
|
|
70
|
+
* @param language - Language code to fetch
|
|
71
|
+
* @returns Promise with translation data
|
|
72
|
+
*/
|
|
73
|
+
fetchTranslations(language) {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
try {
|
|
76
|
+
const response = yield fetch(this.getTranslationUrl(language));
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new Error(`Failed to fetch translations for ${language}`);
|
|
79
|
+
}
|
|
80
|
+
return yield response.json();
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.warn(`Failed to fetch translations for ${language}:`, error);
|
|
84
|
+
// Fallback to English if available
|
|
85
|
+
if (language !== 'en') {
|
|
86
|
+
try {
|
|
87
|
+
return yield this.fetchTranslations('en');
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.warn('Failed to fetch fallback translations:', error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get translation for a key
|
|
99
|
+
* @param key - Translation key
|
|
100
|
+
* @param options - Translation options
|
|
101
|
+
* @returns Translated string
|
|
102
|
+
*/
|
|
103
|
+
t(key, options) {
|
|
104
|
+
return i18n.t(key, options);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get current language
|
|
108
|
+
*/
|
|
109
|
+
getCurrentLanguage() {
|
|
110
|
+
return this.currentLanguage;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if translator is initialized
|
|
114
|
+
*/
|
|
115
|
+
isReady() {
|
|
116
|
+
return this.isInitialized;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import i18n, { createInstance } from 'i18next';
|
|
2
|
+
import { initReactI18next } from 'react-i18next';
|
|
3
|
+
/**
|
|
4
|
+
* Initialize i18n with or without React support
|
|
5
|
+
* @param isReact - Whether to use React-specific features
|
|
6
|
+
*/
|
|
7
|
+
export function getI18n(isReact = false) {
|
|
8
|
+
const i18n = createInstance({
|
|
9
|
+
fallbackLng: 'en',
|
|
10
|
+
debug: window.location.hostname === 'localhost',
|
|
11
|
+
interpolation: {
|
|
12
|
+
escapeValue: !isReact,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
if (isReact) {
|
|
16
|
+
i18n.use(initReactI18next);
|
|
17
|
+
}
|
|
18
|
+
return i18n;
|
|
19
|
+
}
|
|
20
|
+
export default i18n;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { I18nConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a configured i18next instance for Rimori plugins
|
|
4
|
+
* @param config - Configuration options for i18n
|
|
5
|
+
* @returns Configured i18next instance
|
|
6
|
+
*/
|
|
7
|
+
export declare const createI18nInstance: (config?: I18nConfig) => import("i18next").i18n;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import i18n from 'i18next';
|
|
2
|
+
import { initReactI18next } from 'react-i18next';
|
|
3
|
+
import HttpBackend from 'i18next-http-backend';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a configured i18next instance for Rimori plugins
|
|
6
|
+
* @param config - Configuration options for i18n
|
|
7
|
+
* @returns Configured i18next instance
|
|
8
|
+
*/
|
|
9
|
+
export const createI18nInstance = (config = {}) => {
|
|
10
|
+
const { fallbackLng = 'en', debug = false, loadPath = './locales/{{lng}}/translation.json', supportedLanguages = ['en', 'es', 'zh', 'hi', 'ar'], namespace = 'translation', } = config;
|
|
11
|
+
i18n
|
|
12
|
+
.use(HttpBackend)
|
|
13
|
+
.use(initReactI18next)
|
|
14
|
+
.init({
|
|
15
|
+
fallbackLng,
|
|
16
|
+
debug,
|
|
17
|
+
supportedLngs: supportedLanguages,
|
|
18
|
+
ns: [namespace],
|
|
19
|
+
defaultNS: namespace,
|
|
20
|
+
backend: {
|
|
21
|
+
loadPath,
|
|
22
|
+
},
|
|
23
|
+
interpolation: {
|
|
24
|
+
escapeValue: false, // React already escapes by default
|
|
25
|
+
},
|
|
26
|
+
react: {
|
|
27
|
+
useSuspense: true,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
return i18n;
|
|
31
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TOptions } from 'i18next';
|
|
2
|
+
type TranslatorFn = (key: string, options?: TOptions) => string;
|
|
3
|
+
/**
|
|
4
|
+
* Custom useTranslation hook that provides a translation function and indicates readiness
|
|
5
|
+
* @returns An object containing the translation function (`t`) and a boolean (`ready`) indicating if the translator is initialized.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useTranslation(): {
|
|
8
|
+
t: TranslatorFn;
|
|
9
|
+
ready: boolean;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useRimori } from '../providers/PluginProvider';
|
|
3
|
+
/**
|
|
4
|
+
* Custom useTranslation hook that provides a translation function and indicates readiness
|
|
5
|
+
* @returns An object containing the translation function (`t`) and a boolean (`ready`) indicating if the translator is initialized.
|
|
6
|
+
*/
|
|
7
|
+
export function useTranslation() {
|
|
8
|
+
const { plugin } = useRimori();
|
|
9
|
+
const [translatorInstance, setTranslatorInstance] = useState(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
void plugin.getTranslator().then(setTranslatorInstance);
|
|
12
|
+
}, [plugin]);
|
|
13
|
+
const safeT = (key, options) => {
|
|
14
|
+
if (!translatorInstance)
|
|
15
|
+
return '\u200B'; // zero-width space
|
|
16
|
+
try {
|
|
17
|
+
return translatorInstance.t(key, options);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error('Translation error:', error);
|
|
21
|
+
return key;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return { t: safeT, ready: translatorInstance !== null };
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom hook that automatically initializes i18n with user's language
|
|
3
|
+
* and provides the useTranslation hook functionality
|
|
4
|
+
* @param namespace - Optional namespace for translations
|
|
5
|
+
* @returns useTranslation hook result
|
|
6
|
+
*/
|
|
7
|
+
export declare const useRimoriI18n: (namespace?: string) => {
|
|
8
|
+
t: import("i18next").TFunction<string, undefined>;
|
|
9
|
+
i18n: import("i18next").i18n;
|
|
10
|
+
ready: boolean;
|
|
11
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { useEffect } from 'react';
|
|
11
|
+
import { useTranslation } from 'react-i18next';
|
|
12
|
+
import { useRimori } from '../providers/PluginProvider';
|
|
13
|
+
/**
|
|
14
|
+
* Custom hook that automatically initializes i18n with user's language
|
|
15
|
+
* and provides the useTranslation hook functionality
|
|
16
|
+
* @param namespace - Optional namespace for translations
|
|
17
|
+
* @returns useTranslation hook result
|
|
18
|
+
*/
|
|
19
|
+
export const useRimoriI18n = (namespace) => {
|
|
20
|
+
const { t, i18n, ready } = useTranslation(namespace);
|
|
21
|
+
const rimoriClient = useRimori();
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const initializeLanguage = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
try {
|
|
25
|
+
const userInfo = rimoriClient.plugin.getUserInfo();
|
|
26
|
+
const userLanguage = userInfo.mother_tongue.code.toLowerCase();
|
|
27
|
+
// Only change language if it's different from current
|
|
28
|
+
if (i18n.language !== userLanguage) {
|
|
29
|
+
yield i18n.changeLanguage(userLanguage);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.warn('Failed to initialize i18n with user language, using fallback:', error);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
if (ready) {
|
|
37
|
+
initializeLanguage();
|
|
38
|
+
}
|
|
39
|
+
}, [i18n, rimoriClient, ready]);
|
|
40
|
+
return { t, i18n, ready };
|
|
41
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from './providers/PluginProvider';
|
|
|
5
5
|
export * from './cli/types/DatabaseTypes';
|
|
6
6
|
export * from './utils/difficultyConverter';
|
|
7
7
|
export * from './utils/PluginUtils';
|
|
8
|
-
export * from './utils/Language';
|
|
9
8
|
export * from './fromRimori/PluginTypes';
|
|
10
9
|
export { FirstMessages } from './components/ai/utils';
|
|
11
10
|
export { AudioController } from './plugin/AudioController';
|
|
11
|
+
export { useTranslation } from './hooks/I18nHooks';
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,6 @@ export * from './providers/PluginProvider';
|
|
|
6
6
|
export * from './cli/types/DatabaseTypes';
|
|
7
7
|
export * from './utils/difficultyConverter';
|
|
8
8
|
export * from './utils/PluginUtils';
|
|
9
|
-
export * from './utils/Language';
|
|
10
9
|
export * from './fromRimori/PluginTypes';
|
|
11
10
|
export { AudioController } from './plugin/AudioController';
|
|
11
|
+
export { useTranslation } from './hooks/I18nHooks';
|
|
@@ -9,6 +9,7 @@ import { EventBusMessage, EventHandler, EventPayload } from '../fromRimori/Event
|
|
|
9
9
|
import { ActivePlugin, MainPanelAction, Plugin, Tool } from '../fromRimori/PluginTypes';
|
|
10
10
|
import { AccomplishmentPayload } from './AccomplishmentHandler';
|
|
11
11
|
import { PluginController } from './PluginController';
|
|
12
|
+
import { Translator } from './TranslationController';
|
|
12
13
|
interface Db {
|
|
13
14
|
from: {
|
|
14
15
|
<TableName extends string & keyof GenericSchema['Tables'], Table extends GenericSchema['Tables'][TableName]>(relation: TableName): PostgrestQueryBuilder<GenericSchema, Table, TableName>;
|
|
@@ -57,6 +58,7 @@ interface PluginInterface {
|
|
|
57
58
|
sidePanelPlugin?: ActivePlugin;
|
|
58
59
|
};
|
|
59
60
|
getUserInfo: () => UserInfo;
|
|
61
|
+
getTranslator: () => Promise<Translator>;
|
|
60
62
|
}
|
|
61
63
|
export declare class RimoriClient {
|
|
62
64
|
private static instance;
|
|
@@ -67,6 +69,7 @@ export declare class RimoriClient {
|
|
|
67
69
|
private exerciseController;
|
|
68
70
|
private accomplishmentHandler;
|
|
69
71
|
private rimoriInfo;
|
|
72
|
+
private translator;
|
|
70
73
|
plugin: PluginInterface;
|
|
71
74
|
db: Db;
|
|
72
75
|
private constructor();
|
|
@@ -15,6 +15,7 @@ import { getSTTResponse, getTTSResponse } from '../core/controller/VoiceControll
|
|
|
15
15
|
import { ExerciseController } from '../core/controller/ExerciseController';
|
|
16
16
|
import { EventBus } from '../fromRimori/EventBus';
|
|
17
17
|
import { AccomplishmentHandler } from './AccomplishmentHandler';
|
|
18
|
+
import { Translator } from './TranslationController';
|
|
18
19
|
export class RimoriClient {
|
|
19
20
|
constructor(supabase, info, pluginController) {
|
|
20
21
|
this.event = {
|
|
@@ -250,6 +251,7 @@ export class RimoriClient {
|
|
|
250
251
|
this.sharedContentController = new SharedContentController(this.superbase, this);
|
|
251
252
|
this.exerciseController = new ExerciseController(supabase, pluginController);
|
|
252
253
|
this.accomplishmentHandler = new AccomplishmentHandler(info.pluginId);
|
|
254
|
+
this.translator = new Translator(info.profile.mother_tongue.code);
|
|
253
255
|
this.from = this.from.bind(this);
|
|
254
256
|
this.getTableName = this.getTableName.bind(this);
|
|
255
257
|
this.db = {
|
|
@@ -277,6 +279,10 @@ export class RimoriClient {
|
|
|
277
279
|
sidePanelPlugin: this.rimoriInfo.sidePanelPlugin,
|
|
278
280
|
};
|
|
279
281
|
},
|
|
282
|
+
getTranslator: () => __awaiter(this, void 0, void 0, function* () {
|
|
283
|
+
yield this.translator.initialize();
|
|
284
|
+
return this.translator;
|
|
285
|
+
}),
|
|
280
286
|
};
|
|
281
287
|
}
|
|
282
288
|
/**
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ThirdPartyModule, TOptions } from 'i18next';
|
|
2
|
+
/**
|
|
3
|
+
* Translator class for handling internationalization
|
|
4
|
+
*/
|
|
5
|
+
export declare class Translator {
|
|
6
|
+
private currentLanguage;
|
|
7
|
+
private isInitialized;
|
|
8
|
+
private i18n;
|
|
9
|
+
constructor(initialLanguage: string);
|
|
10
|
+
/**
|
|
11
|
+
* Initialize translator with user's language
|
|
12
|
+
* @param userLanguage - Language code from user info
|
|
13
|
+
*/
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
private getTranslationUrl;
|
|
16
|
+
usePlugin(plugin: ThirdPartyModule): void;
|
|
17
|
+
/**
|
|
18
|
+
* Fetch translations manually from the current domain
|
|
19
|
+
* @param language - Language code to fetch
|
|
20
|
+
* @returns Promise with translation data
|
|
21
|
+
*/
|
|
22
|
+
private fetchTranslations;
|
|
23
|
+
/**
|
|
24
|
+
* Get translation for a key
|
|
25
|
+
* @param key - Translation key
|
|
26
|
+
* @param options - Translation options
|
|
27
|
+
* @returns Translated string
|
|
28
|
+
*/
|
|
29
|
+
t(key: string, options?: TOptions): string;
|
|
30
|
+
/**
|
|
31
|
+
* Get current language
|
|
32
|
+
*/
|
|
33
|
+
getCurrentLanguage(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Check if translator is initialized
|
|
36
|
+
*/
|
|
37
|
+
isReady(): boolean;
|
|
38
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { createInstance } from 'i18next';
|
|
11
|
+
/**
|
|
12
|
+
* Translator class for handling internationalization
|
|
13
|
+
*/
|
|
14
|
+
export class Translator {
|
|
15
|
+
constructor(initialLanguage) {
|
|
16
|
+
this.isInitialized = false;
|
|
17
|
+
this.currentLanguage = initialLanguage;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Initialize translator with user's language
|
|
21
|
+
* @param userLanguage - Language code from user info
|
|
22
|
+
*/
|
|
23
|
+
initialize() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
if (this.isInitialized)
|
|
26
|
+
return;
|
|
27
|
+
const translations = yield this.fetchTranslations(this.currentLanguage);
|
|
28
|
+
const instance = createInstance({
|
|
29
|
+
lng: this.currentLanguage,
|
|
30
|
+
resources: {
|
|
31
|
+
[this.currentLanguage]: {
|
|
32
|
+
translation: translations,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
debug: window.location.hostname === 'localhost',
|
|
36
|
+
});
|
|
37
|
+
yield instance.init();
|
|
38
|
+
this.i18n = instance;
|
|
39
|
+
this.isInitialized = true;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
getTranslationUrl(language) {
|
|
43
|
+
// For localhost development, use local- prefix for non-English languages
|
|
44
|
+
const isLocalhost = window.location.hostname === 'localhost';
|
|
45
|
+
const isEnglish = language === 'en';
|
|
46
|
+
const filename = isLocalhost && !isEnglish ? `local-${language}` : language;
|
|
47
|
+
return `${window.location.origin}/locales/${filename}.json`;
|
|
48
|
+
}
|
|
49
|
+
usePlugin(plugin) {
|
|
50
|
+
if (!this.i18n) {
|
|
51
|
+
throw new Error('Translator is not initialized');
|
|
52
|
+
}
|
|
53
|
+
this.i18n.use(plugin);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Fetch translations manually from the current domain
|
|
57
|
+
* @param language - Language code to fetch
|
|
58
|
+
* @returns Promise with translation data
|
|
59
|
+
*/
|
|
60
|
+
fetchTranslations(language) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
try {
|
|
63
|
+
const response = yield fetch(this.getTranslationUrl(language));
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new Error(`Failed to fetch translations for ${language}`);
|
|
66
|
+
}
|
|
67
|
+
return (yield response.json());
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.warn(`Failed to fetch translations for ${language}:`, error);
|
|
71
|
+
if (language === 'en')
|
|
72
|
+
return {};
|
|
73
|
+
// Fallback to English
|
|
74
|
+
return this.fetchTranslations('en').catch((error) => {
|
|
75
|
+
console.error('Failed to fetch fallback translations:', error);
|
|
76
|
+
return {};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get translation for a key
|
|
83
|
+
* @param key - Translation key
|
|
84
|
+
* @param options - Translation options
|
|
85
|
+
* @returns Translated string
|
|
86
|
+
*/
|
|
87
|
+
t(key, options) {
|
|
88
|
+
if (!this.i18n) {
|
|
89
|
+
throw new Error('Translator is not initialized');
|
|
90
|
+
}
|
|
91
|
+
return this.i18n.t(key, options);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get current language
|
|
95
|
+
*/
|
|
96
|
+
getCurrentLanguage() {
|
|
97
|
+
return this.currentLanguage;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if translator is initialized
|
|
101
|
+
*/
|
|
102
|
+
isReady() {
|
|
103
|
+
return this.isInitialized;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ThirdPartyModule, TOptions } from 'i18next';
|
|
2
|
+
/**
|
|
3
|
+
* Translator class for handling internationalization
|
|
4
|
+
*/
|
|
5
|
+
export declare class Translator {
|
|
6
|
+
private currentLanguage;
|
|
7
|
+
private isInitialized;
|
|
8
|
+
private i18n;
|
|
9
|
+
constructor(initialLanguage: string);
|
|
10
|
+
/**
|
|
11
|
+
* Initialize translator with user's language
|
|
12
|
+
* @param userLanguage - Language code from user info
|
|
13
|
+
*/
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
private getTranslationUrl;
|
|
16
|
+
usePlugin(plugin: ThirdPartyModule): void;
|
|
17
|
+
/**
|
|
18
|
+
* Fetch translations manually from the current domain
|
|
19
|
+
* @param language - Language code to fetch
|
|
20
|
+
* @returns Promise with translation data
|
|
21
|
+
*/
|
|
22
|
+
private fetchTranslations;
|
|
23
|
+
/**
|
|
24
|
+
* Get translation for a key
|
|
25
|
+
* @param key - Translation key
|
|
26
|
+
* @param options - Translation options
|
|
27
|
+
* @returns Translated string
|
|
28
|
+
*/
|
|
29
|
+
t(key: string, options?: TOptions): string;
|
|
30
|
+
/**
|
|
31
|
+
* Get current language
|
|
32
|
+
*/
|
|
33
|
+
getCurrentLanguage(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Check if translator is initialized
|
|
36
|
+
*/
|
|
37
|
+
isReady(): boolean;
|
|
38
|
+
}
|