@rimori/client 1.4.5 → 1.4.8

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.
Files changed (64) hide show
  1. package/README.md +116 -0
  2. package/dist/cli/scripts/release/detect-translation-languages.d.ts +5 -0
  3. package/dist/cli/scripts/release/detect-translation-languages.js +43 -0
  4. package/dist/cli/scripts/release/release-config-upload.js +4 -0
  5. package/dist/cli/scripts/release/release-translation-upload.d.ts +6 -0
  6. package/dist/cli/scripts/release/release-translation-upload.js +87 -0
  7. package/dist/cli/scripts/release/release.d.ts +1 -1
  8. package/dist/cli/scripts/release/release.js +14 -5
  9. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +2 -2
  10. package/dist/core/controller/EnhancedUserInfo.d.ts +0 -0
  11. package/dist/core/controller/EnhancedUserInfo.js +1 -0
  12. package/dist/core/controller/SettingsController.d.ts +7 -1
  13. package/dist/core/core.d.ts +1 -2
  14. package/dist/core/core.js +0 -1
  15. package/dist/fromRimori/EventBus.js +23 -23
  16. package/dist/fromRimori/PluginTypes.d.ts +4 -4
  17. package/dist/hooks/I18nHooks.d.ts +11 -0
  18. package/dist/hooks/I18nHooks.js +25 -0
  19. package/dist/i18n/I18nHooks.d.ts +11 -0
  20. package/dist/i18n/I18nHooks.js +25 -0
  21. package/dist/i18n/Translator.d.ts +43 -0
  22. package/dist/i18n/Translator.js +118 -0
  23. package/dist/i18n/config.d.ts +7 -0
  24. package/dist/i18n/config.js +20 -0
  25. package/dist/i18n/createI18nInstance.d.ts +7 -0
  26. package/dist/i18n/createI18nInstance.js +31 -0
  27. package/dist/i18n/hooks.d.ts +11 -0
  28. package/dist/i18n/hooks.js +25 -0
  29. package/dist/i18n/index.d.ts +4 -0
  30. package/dist/i18n/index.js +4 -0
  31. package/dist/i18n/types.d.ts +7 -0
  32. package/dist/i18n/types.js +1 -0
  33. package/dist/i18n/useRimoriI18n.d.ts +11 -0
  34. package/dist/i18n/useRimoriI18n.js +41 -0
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +1 -1
  37. package/dist/plugin/RimoriClient.d.ts +3 -0
  38. package/dist/plugin/RimoriClient.js +6 -0
  39. package/dist/plugin/TranslationController.d.ts +38 -0
  40. package/dist/plugin/TranslationController.js +105 -0
  41. package/dist/plugin/Translator.d.ts +38 -0
  42. package/dist/plugin/Translator.js +101 -0
  43. package/dist/utils/LanguageClass.d.ts +36 -0
  44. package/dist/utils/LanguageClass.example.d.ts +0 -0
  45. package/dist/utils/LanguageClass.example.js +1 -0
  46. package/dist/utils/LanguageClass.js +50 -0
  47. package/dist/utils/LanguageClass.test.d.ts +0 -0
  48. package/dist/utils/LanguageClass.test.js +1 -0
  49. package/package.json +12 -14
  50. package/prettier.config.js +1 -1
  51. package/src/cli/scripts/release/detect-translation-languages.ts +37 -0
  52. package/src/cli/scripts/release/release-config-upload.ts +5 -0
  53. package/src/cli/scripts/release/release.ts +20 -4
  54. package/src/cli/types/DatabaseTypes.ts +10 -2
  55. package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +2 -2
  56. package/src/core/controller/SettingsController.ts +8 -1
  57. package/src/core/core.ts +1 -2
  58. package/src/fromRimori/EventBus.ts +47 -76
  59. package/src/fromRimori/PluginTypes.ts +17 -26
  60. package/src/hooks/I18nHooks.ts +33 -0
  61. package/src/index.ts +1 -1
  62. package/src/plugin/RimoriClient.ts +9 -1
  63. package/src/plugin/TranslationController.ts +105 -0
  64. package/src/utils/Language.ts +0 -72
@@ -0,0 +1,101 @@
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
+ return `${window.location.origin}/locales/${language}/translation.json`;
44
+ }
45
+ usePlugin(plugin) {
46
+ if (!this.i18n) {
47
+ throw new Error('Translator is not initialized');
48
+ }
49
+ this.i18n.use(plugin);
50
+ }
51
+ /**
52
+ * Fetch translations manually from the current domain
53
+ * @param language - Language code to fetch
54
+ * @returns Promise with translation data
55
+ */
56
+ fetchTranslations(language) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ try {
59
+ const response = yield fetch(this.getTranslationUrl(language));
60
+ if (!response.ok) {
61
+ throw new Error(`Failed to fetch translations for ${language}`);
62
+ }
63
+ return (yield response.json());
64
+ }
65
+ catch (error) {
66
+ console.warn(`Failed to fetch translations for ${language}:`, error);
67
+ if (language === 'en')
68
+ return {};
69
+ // Fallback to English
70
+ return this.fetchTranslations('en').catch((error) => {
71
+ console.error('Failed to fetch fallback translations:', error);
72
+ return {};
73
+ });
74
+ }
75
+ });
76
+ }
77
+ /**
78
+ * Get translation for a key
79
+ * @param key - Translation key
80
+ * @param options - Translation options
81
+ * @returns Translated string
82
+ */
83
+ t(key, options) {
84
+ if (!this.i18n) {
85
+ throw new Error('Translator is not initialized');
86
+ }
87
+ return this.i18n.t(key, options);
88
+ }
89
+ /**
90
+ * Get current language
91
+ */
92
+ getCurrentLanguage() {
93
+ return this.currentLanguage;
94
+ }
95
+ /**
96
+ * Check if translator is initialized
97
+ */
98
+ isReady() {
99
+ return this.isInitialized;
100
+ }
101
+ }
@@ -0,0 +1,36 @@
1
+ import { Language } from './Language';
2
+ /**
3
+ * A class that represents a language with dual functionality:
4
+ * - When converted to string, returns the 2-letter language code
5
+ * - When used as an object, provides getters for different language representations
6
+ */
7
+ export declare class LanguageClass {
8
+ private readonly languageCode;
9
+ constructor(languageCode: Language);
10
+ /**
11
+ * Returns the 2-letter language code when the object is converted to string
12
+ */
13
+ toString(): string;
14
+ /**
15
+ * Returns the 2-letter language code
16
+ */
17
+ get code(): string;
18
+ /**
19
+ * Returns the full language name in lowercase
20
+ */
21
+ get name(): string;
22
+ /**
23
+ * Returns the full language name with first letter capitalized
24
+ */
25
+ get capitalized(): string;
26
+ /**
27
+ * Returns the full language name in uppercase
28
+ */
29
+ get uppercase(): string;
30
+ }
31
+ /**
32
+ * Creates a LanguageClass instance from a language code
33
+ * @param languageCode The 2-letter language code
34
+ * @returns A LanguageClass instance
35
+ */
36
+ export declare function createLanguage(languageCode: Language): LanguageClass;
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,50 @@
1
+ import { languageKeys } from './Language';
2
+ /**
3
+ * A class that represents a language with dual functionality:
4
+ * - When converted to string, returns the 2-letter language code
5
+ * - When used as an object, provides getters for different language representations
6
+ */
7
+ export class LanguageClass {
8
+ constructor(languageCode) {
9
+ this.languageCode = languageCode;
10
+ }
11
+ /**
12
+ * Returns the 2-letter language code when the object is converted to string
13
+ */
14
+ toString() {
15
+ return this.languageCode;
16
+ }
17
+ /**
18
+ * Returns the 2-letter language code
19
+ */
20
+ get code() {
21
+ return this.languageCode;
22
+ }
23
+ /**
24
+ * Returns the full language name in lowercase
25
+ */
26
+ get name() {
27
+ return languageKeys[this.languageCode];
28
+ }
29
+ /**
30
+ * Returns the full language name with first letter capitalized
31
+ */
32
+ get capitalized() {
33
+ const lang = languageKeys[this.languageCode];
34
+ return lang.charAt(0).toUpperCase() + lang.slice(1);
35
+ }
36
+ /**
37
+ * Returns the full language name in uppercase
38
+ */
39
+ get uppercase() {
40
+ return languageKeys[this.languageCode].toUpperCase();
41
+ }
42
+ }
43
+ /**
44
+ * Creates a LanguageClass instance from a language code
45
+ * @param languageCode The 2-letter language code
46
+ * @returns A LanguageClass instance
47
+ */
48
+ export function createLanguage(languageCode) {
49
+ return new LanguageClass(languageCode);
50
+ }
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimori/client",
3
- "version": "1.4.5",
3
+ "version": "1.4.8",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "bin": {
@@ -26,11 +26,8 @@
26
26
  "build": "tsc && sass src/style.scss:dist/style.css",
27
27
  "dev": "tsc -w --preserveWatchOutput",
28
28
  "css-dev": "sass --watch src/style.scss:dist/style.css",
29
- "lint": "eslint .",
30
- "lint:fix": "eslint . --fix",
31
- "format": "prettier --write .",
32
- "format:check": "prettier --check .",
33
- "check": "yarn lint && yarn format:check"
29
+ "lint": "eslint . --fix",
30
+ "format": "prettier --write ."
34
31
  },
35
32
  "peerDependencies": {
36
33
  "react": "^18.0.0",
@@ -42,22 +39,23 @@
42
39
  "@tiptap/starter-kit": "2.10.3",
43
40
  "dotenv": "16.5.0",
44
41
  "html2canvas": "1.4.1",
42
+ "i18next": "^25.6.0",
43
+ "prettier": "^3.6.2",
45
44
  "react-icons": "5.4.0",
46
45
  "react-markdown": "10.1.0",
47
- "tiptap-markdown": "0.8.10",
48
- "prettier": "^3.6.2"
46
+ "tiptap-markdown": "0.8.10"
49
47
  },
50
48
  "devDependencies": {
51
- "form-data": "^4.0.2",
52
- "node-fetch": "^3.3.2",
53
- "sass": "^1.82.0",
54
- "typescript": "^5.7.2",
55
49
  "@eslint/js": "^9.37.0",
50
+ "eslint-config-prettier": "^10.1.8",
51
+ "eslint-plugin-prettier": "^5.5.4",
56
52
  "eslint-plugin-react-hooks": "^7.0.0",
57
53
  "eslint-plugin-react-refresh": "^0.4.23",
58
- "eslint-plugin-prettier": "^5.5.4",
59
- "eslint-config-prettier": "^10.1.8",
54
+ "form-data": "^4.0.2",
60
55
  "globals": "^16.4.0",
56
+ "node-fetch": "^3.3.2",
57
+ "sass": "^1.82.0",
58
+ "typescript": "^5.7.2",
61
59
  "typescript-eslint": "^8.46.0"
62
60
  }
63
61
  }
@@ -1,7 +1,7 @@
1
1
  export default {
2
2
  printWidth: 120,
3
3
  singleQuote: true,
4
- trailingComma: 'all',
4
+ trailingComma: "all",
5
5
  semi: true,
6
6
  tabWidth: 2,
7
7
  useTabs: false,
@@ -0,0 +1,37 @@
1
+ import fs from 'fs';
2
+
3
+ /**
4
+ * Detect available translation languages from public/locales directory
5
+ * @returns Promise<string[]> Array of language codes found in the locales directory
6
+ */
7
+ export async function detectTranslationLanguages(): Promise<string[]> {
8
+ const localesPath = './public/locales';
9
+
10
+ try {
11
+ await fs.promises.access(localesPath);
12
+ } catch (e) {
13
+ console.log('⚠️ No locales directory found, no translations available');
14
+ return [];
15
+ }
16
+
17
+ try {
18
+ const files = await fs.promises.readdir(localesPath);
19
+
20
+ // Filter out local- files and only include .json files
21
+ const translationFiles = files.filter((file) => file.endsWith('.json') && !file.startsWith('local-'));
22
+
23
+ if (translationFiles.length === 0) {
24
+ console.log('⚠️ No translation files found (excluding local- files)');
25
+ return [];
26
+ }
27
+
28
+ // Extract language codes from filenames (e.g., en.json -> en)
29
+ const languages = translationFiles.map((file) => file.replace('.json', ''));
30
+
31
+ console.log(`🌐 Found ${languages.length} translation languages: ${languages.join(', ')}`);
32
+ return languages;
33
+ } catch (error: any) {
34
+ console.error(`❌ Error reading locales directory:`, error.message);
35
+ return [];
36
+ }
37
+ }
@@ -2,6 +2,7 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import ts from 'typescript';
4
4
  import { Config } from './release.js';
5
+ import { detectTranslationLanguages } from './detect-translation-languages.js';
5
6
 
6
7
  /**
7
8
  * Read and send the rimori configuration to the release endpoint
@@ -52,6 +53,9 @@ export async function sendConfiguration(config: Config): Promise<string> {
52
53
  throw new Error('Configuration object is empty or undefined');
53
54
  }
54
55
 
56
+ // Detect available translation languages
57
+ const availableLanguages = await detectTranslationLanguages();
58
+
55
59
  console.log(`🚀 Sending configuration...`);
56
60
 
57
61
  const requestBody = {
@@ -60,6 +64,7 @@ export async function sendConfiguration(config: Config): Promise<string> {
60
64
  plugin_id: config.plugin_id,
61
65
  release_channel: config.release_channel,
62
66
  rimori_client_version: config.rimori_client_version,
67
+ provided_languages: availableLanguages.join(','),
63
68
  };
64
69
 
65
70
  try {
@@ -5,7 +5,7 @@
5
5
  * rimori-release <release_channel>
6
6
  *
7
7
  * Environment variables required:
8
- * RIMORI_TOKEN - Your Rimori token
8
+ * RIMORI_TOKEN - Your Rimori token
9
9
  * RIMORI_PLUGIN - Your plugin ID
10
10
  *
11
11
  * Make sure to install dependencies:
@@ -22,10 +22,16 @@ import { releasePlugin, sendConfiguration } from './release-config-upload.js';
22
22
  // Read version from package.json
23
23
  const packageJson = JSON.parse(fs.readFileSync(path.resolve('./package.json'), 'utf8'));
24
24
  const { version, r_id: pluginId } = packageJson;
25
-
26
25
  const RIMORI_TOKEN = process.env.RIMORI_TOKEN;
27
- if (!RIMORI_TOKEN) throw new Error('RIMORI_TOKEN is not set');
28
- if (!pluginId) throw new Error('The plugin id (r_id) is not set in package.json');
26
+
27
+ if (!RIMORI_TOKEN) {
28
+ console.error('Error: RIMORI_TOKEN is not set');
29
+ process.exit(1);
30
+ }
31
+ if (!pluginId) {
32
+ console.error('Error: The plugin id (r_id) is not set in package.json');
33
+ process.exit(1);
34
+ }
29
35
 
30
36
  const [releaseChannel] = process.argv.slice(2);
31
37
  if (!releaseChannel) {
@@ -33,6 +39,10 @@ if (!releaseChannel) {
33
39
  process.exit(1);
34
40
  }
35
41
 
42
+ if (process.env.RIMORI_BACKEND_URL) {
43
+ console.info('Using backend url:', process.env.RIMORI_BACKEND_URL);
44
+ }
45
+
36
46
  const config = {
37
47
  version,
38
48
  release_channel: releaseChannel,
@@ -50,6 +60,7 @@ export type Config = typeof config;
50
60
  async function releaseProcess(): Promise<void> {
51
61
  try {
52
62
  console.log(`🚀 Releasing ${config.plugin_id} to ${config.release_channel}...`);
63
+
53
64
  // First send the configuration
54
65
  const release_id = await sendConfiguration(config);
55
66
 
@@ -60,6 +71,11 @@ async function releaseProcess(): Promise<void> {
60
71
 
61
72
  // Then release the plugin
62
73
  await releasePlugin(config, release_id);
74
+
75
+ // Inform user about translation processing
76
+ console.log(
77
+ '🌐 Hint: The plugin is released but it might take some time until all translations are being processed.',
78
+ );
63
79
  } catch (error: any) {
64
80
  console.log('❌ Error:', error.message);
65
81
  process.exit(1);
@@ -3,7 +3,14 @@
3
3
  /**
4
4
  * Supported database column data types for table schema definitions.
5
5
  */
6
- type DbColumnType = 'decimal' | 'integer' | 'text' | 'boolean' | 'json' | 'timestamp' | 'uuid';
6
+ type DbColumnType =
7
+ | 'decimal'
8
+ | 'integer'
9
+ | 'text'
10
+ | 'boolean'
11
+ | 'json'
12
+ | 'timestamp'
13
+ | 'uuid';
7
14
 
8
15
  /**
9
16
  * Foreign key relationship configuration with cascade delete support.
@@ -113,4 +120,5 @@ export interface DbPermissionDefinition {
113
120
  /**
114
121
  * Full table definition that includes automatically generated fields.
115
122
  */
116
- export type FullTable<T extends Record<string, DbColumnDefinition>> = T & BaseTableStructure;
123
+ export type FullTable<T extends Record<string, DbColumnDefinition>> = T &
124
+ BaseTableStructure;
@@ -18,9 +18,9 @@ export class MessageSender {
18
18
  }
19
19
 
20
20
  private getCompletedSentences(currentText: string, isLoading: boolean): string[] {
21
- // Split the text based on the following characters: .,?!
21
+ // Split the text based on the following characters: .?!
22
22
  // Only split on : when followed by a space
23
- const pattern = /(.+?[,.?!]|.+?:\s+|.+?\n+)/g;
23
+ const pattern = /(.+?[.?!]|.+?:\s+|.+?\n+)/g;
24
24
  const result: string[] = [];
25
25
  let match;
26
26
  while ((match = pattern.exec(currentText)) !== null) {
@@ -1,6 +1,5 @@
1
1
  import { SupabaseClient } from '@supabase/supabase-js';
2
2
  import { LanguageLevel } from '../../utils/difficultyConverter';
3
- import { Language } from '../../utils/Language';
4
3
  import { Guild } from '../core';
5
4
 
6
5
  export interface Buddy {
@@ -12,6 +11,14 @@ export interface Buddy {
12
11
  aiPersonality: string;
13
12
  }
14
13
 
14
+ export interface Language {
15
+ code: string;
16
+ name: string;
17
+ native: string;
18
+ capitalized: string;
19
+ uppercase: string;
20
+ }
21
+
15
22
  export interface UserInfo {
16
23
  skill_level_reading: LanguageLevel;
17
24
  skill_level_writing: LanguageLevel;
package/src/core/core.ts CHANGED
@@ -3,11 +3,10 @@ export * from '../fromRimori/PluginTypes';
3
3
  export * from '../plugin/PluginController';
4
4
  export * from '../plugin/RimoriClient';
5
5
  export * from '../utils/difficultyConverter';
6
- export * from '../utils/Language';
7
6
  export * from '../utils/PluginUtils';
8
7
  export * from '../worker/WorkerSetup';
9
8
  export { EventBusMessage } from '../fromRimori/EventBus';
10
- export { Buddy, UserInfo } from './controller/SettingsController';
9
+ export { Buddy, UserInfo, Language } from './controller/SettingsController';
11
10
  export { SharedContent } from './controller/SharedContentController';
12
11
  export { Exercise, TriggerAction } from './controller/ExerciseController';
13
12
  export { Message, OnLLMResponse, ToolInvocation } from './controller/AIController';