diff --git a/packages/core/src/Application.ts b/packages/core/src/Application.ts index 3b05d1e..b06cde5 100644 --- a/packages/core/src/Application.ts +++ b/packages/core/src/Application.ts @@ -11,6 +11,10 @@ export class Application implements IApplication, IApplicationRegistration { this.container.bind(identifier).toConstantValue(service); } + public registerConstantMultiple(service: T, identifier: symbol) { + this.container.bind(identifier).toConstantValue(service); + } + public register(service: interfaces.Newable, identifier: symbol) { if (this.container.isBound(identifier)) { this.container.unbind(identifier); diff --git a/packages/core/src/IApplicationRegistration.ts b/packages/core/src/IApplicationRegistration.ts index f9b0e4c..fa3dd8e 100644 --- a/packages/core/src/IApplicationRegistration.ts +++ b/packages/core/src/IApplicationRegistration.ts @@ -16,6 +16,13 @@ export interface IApplicationRegistration { */ registerConstant(service: T, identifier: symbol): void; + /** + * Registers a new constant without removing previous registrations. + * @param service service to register. + * @param identifier symbol for the service. + */ + registerConstantMultiple(service: T, identifier: symbol): void; + /** * Registers a {@link IModule}. * @param module {@link IModule} to use in the {@link IApplication}. diff --git a/packages/core/src/Modules/CoreModule.ts b/packages/core/src/Modules/CoreModule.ts index 48da880..75b3069 100644 --- a/packages/core/src/Modules/CoreModule.ts +++ b/packages/core/src/Modules/CoreModule.ts @@ -1,4 +1,4 @@ -import { IIndexManagerSymbol, IKeyValueStoreSymbol, IObjectStoreSymbol, ITranslationServiceSymbol } from 'ipmc-interfaces'; +import { IIndexManagerSymbol, IKeyValueStoreSymbol, IObjectStoreSymbol, ITranslationServiceSymbol, ITranslationsSymbol } from 'ipmc-interfaces'; import { MemoryKeyValueStore } from '../Services/MemoryKeyValueStore'; import { ObjectStore } from '../Services/ObjectStore'; import { IModule } from './IModule'; @@ -6,6 +6,8 @@ import { IndexManager } from '../Services/IndexManager'; import { TaskManager } from '../Services/TaskManager'; import { ITaskManagerSymbol } from 'ipmc-interfaces'; import { TranslationService } from '../Services/TranslationService'; +import en from '../translations/en.json'; +import de from '../translations/de.json'; export const CoreModule: IModule = (app) => { app.register(MemoryKeyValueStore, IKeyValueStoreSymbol); @@ -13,4 +15,12 @@ export const CoreModule: IModule = (app) => { app.register(IndexManager, IIndexManagerSymbol); app.register(TaskManager, ITaskManagerSymbol); app.register(TranslationService, ITranslationServiceSymbol); + app.registerConstantMultiple({ + en: { + translation: en, + }, + de: { + translation: de, + } + }, ITranslationsSymbol); }; diff --git a/packages/core/src/Services/TranslationService.ts b/packages/core/src/Services/TranslationService.ts index 1aadc55..8d683ca 100644 --- a/packages/core/src/Services/TranslationService.ts +++ b/packages/core/src/Services/TranslationService.ts @@ -1,15 +1,25 @@ import i18next from 'i18next'; -import { inject, injectable } from 'inversify'; -import { ITranslationService, ITranslationsSymbol } from 'ipmc-interfaces'; +import { multiInject, injectable, optional } from 'inversify'; +import { ITranslationService, ITranslationsSymbol, ITranslation } from 'ipmc-interfaces'; @injectable() export class TranslationService implements ITranslationService { - constructor(@inject(ITranslationsSymbol) translations: any) { + constructor(@multiInject(ITranslationsSymbol) @optional() translations: ITranslation[]) { + const resources: ITranslation = {}; + for (const translationSet of translations) { + for (const [lang, values] of Object.entries(translationSet)) { + if (!resources.hasOwnProperty(lang)) { + resources[lang] = { translation: {} }; + } + resources[lang].translation = { ...resources[lang].translation, ...values.translation }; + } + } + i18next.init({ - resources: translations, - lng: "en", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources + resources, + lng: "en", interpolation: { - escapeValue: false // react already safes from xss + escapeValue: false } }); } @@ -18,6 +28,7 @@ export class TranslationService implements ITranslationService { if (i18next.exists(key)) { return i18next.t(key, values); } else { + console.warn(`Missing translation key <${key}>`); return `<${key}>`; } } diff --git a/packages/core/src/translations/de.json b/packages/core/src/translations/de.json new file mode 100644 index 0000000..408f29f --- /dev/null +++ b/packages/core/src/translations/de.json @@ -0,0 +1,3 @@ +{ + "UpdatingLibrary": "Aktualisieren von {{name}}" +} diff --git a/packages/core/src/translations/en.json b/packages/core/src/translations/en.json new file mode 100644 index 0000000..a895dc2 --- /dev/null +++ b/packages/core/src/translations/en.json @@ -0,0 +1,3 @@ +{ + "UpdatingLibrary": "Updating library {{name}}" +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index fc9a77e..df44ae8 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -40,7 +40,7 @@ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ + "resolveJsonModule": true, /* Enable importing .json files. */ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ diff --git a/packages/interfaces/src/Services/ITranslationService/ITranslation.ts b/packages/interfaces/src/Services/ITranslationService/ITranslation.ts new file mode 100644 index 0000000..43ab415 --- /dev/null +++ b/packages/interfaces/src/Services/ITranslationService/ITranslation.ts @@ -0,0 +1,9 @@ +export const ITranslationsSymbol = Symbol.for('ITranslations'); + +export type ITranslation = { + [key: string]: { + translation: { + [key: string]: string; + }; + }; +}; diff --git a/packages/interfaces/src/Services/ITranslationService.ts b/packages/interfaces/src/Services/ITranslationService/ITranslationService.ts similarity index 74% rename from packages/interfaces/src/Services/ITranslationService.ts rename to packages/interfaces/src/Services/ITranslationService/ITranslationService.ts index cafab2d..9b5d4cf 100644 --- a/packages/interfaces/src/Services/ITranslationService.ts +++ b/packages/interfaces/src/Services/ITranslationService/ITranslationService.ts @@ -1,7 +1,5 @@ export const ITranslationServiceSymbol = Symbol.for('ITranslationService'); -export const ITranslationsSymbol = Symbol.for('ITranslations'); - export interface ITranslationService { translate(key: string, values?: { [key: string]: string; }): string; } diff --git a/packages/interfaces/src/Services/ITranslationService/index.ts b/packages/interfaces/src/Services/ITranslationService/index.ts new file mode 100644 index 0000000..f8ade6e --- /dev/null +++ b/packages/interfaces/src/Services/ITranslationService/index.ts @@ -0,0 +1,2 @@ +export { type ITranslation, ITranslationsSymbol } from './ITranslation'; +export { type ITranslationService, ITranslationServiceSymbol } from './ITranslationService'; diff --git a/packages/interfaces/src/Services/index.ts b/packages/interfaces/src/Services/index.ts index dd0c866..07d98ec 100644 --- a/packages/interfaces/src/Services/index.ts +++ b/packages/interfaces/src/Services/index.ts @@ -1,4 +1,5 @@ export * from './ITaskManager'; +export * from './ITranslationService'; export { type IConfigurationService } from './IConfigurationService'; export { IHotkeyServiceSymbol, type IHotkeyService, type IHotkey } from './IHotkeyService'; export { type IIndexManager, IIndexManagerSymbol } from './IIndexManager'; @@ -6,4 +7,3 @@ export { type IIpfsService, IIpfsServiceSymbol } from './IIpfsService'; export { type IKeyValueStore, IKeyValueStoreSymbol } from './IKeyValueStore'; export { type INodeService } from './INodeService'; export { type IObjectStore, IObjectStoreSymbol } from './IObjectStore'; -export { type ITranslationService, ITranslationServiceSymbol, ITranslationsSymbol } from './ITranslationService'; diff --git a/packages/ui/src/IpmcApp.tsx b/packages/ui/src/IpmcApp.tsx index 749bf86..1115147 100644 --- a/packages/ui/src/IpmcApp.tsx +++ b/packages/ui/src/IpmcApp.tsx @@ -4,10 +4,10 @@ import { Switch } from 'wouter'; import { AppBar } from './components/organisms/AppBar'; import { LibraryManager } from "./components/pages/LibraryManager"; import { AppContextProvider } from './context'; +import { ITranslationsSymbol, ITranslation } from 'ipmc-interfaces'; // Setup translations import './i18n'; -import { ITranslationsSymbol } from 'ipmc-interfaces'; export interface IIpmcAppProps { setup?: IModule; @@ -33,7 +33,7 @@ export function IpmcApp(props: IIpmcAppProps) { { app.use(CoreModule); app.use(BrowserModule); - app.registerConstant(resources, ITranslationsSymbol); + app.registerConstantMultiple(resources, ITranslationsSymbol); setup && app.use(setup); }}>