Skip to content

Commit

Permalink
refactor: use config providers for resolving config
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Oct 20, 2023
1 parent 8628f89 commit 377daaa
Show file tree
Hide file tree
Showing 17 changed files with 153 additions and 218 deletions.
2 changes: 0 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,3 @@ export { configure } from './configure.js'
export { stubsRoot } from './stubs/main.js'
export { I18nManager } from './src/i18n_manager.js'
export { defineConfig } from './src/define_config.js'
export { default as loadersList } from './src/loaders/main.js'
export { default as formattersList } from './src/formatters/main.js'
24 changes: 21 additions & 3 deletions providers/i18n_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,20 @@
*/

import type { Edge } from 'edge.js'
import { I18nManager } from '../src/i18n_manager.js'
import type { ApplicationService } from '@adonisjs/core/types'
import type { MissingTranslationEventPayload } from '../src/types/main.js'
import { configProvider } from '@adonisjs/core'
import { RuntimeException } from '@poppinss/utils'

import '../src/types/extended.js'
declare module '@adonisjs/core/types' {
export interface EventsList {
'i18n:missing:translation': MissingTranslationEventPayload
}
export interface ContainerBindings {
i18n: I18nManager
}
}

/**
* Registers a singleton instance of I18nManager to the container,
Expand All @@ -36,9 +47,16 @@ export default class I18nProvider {
*/
register() {
this.app.container.singleton('i18n', async (resolver) => {
const { I18nManager } = await import('../src/i18n_manager.js')
const i18nConfigProvider = this.app.config.get('i18n', {})
const config = await configProvider.resolve<any>(this.app, i18nConfigProvider)

if (!config) {
throw new RuntimeException(
'Invalid default export from "config/i18n.ts" file. Make sure to use defineConfig method'
)
}

const emitter = await resolver.make('emitter')
const config = this.app.config.get<any>('i18n', {})
return new I18nManager(emitter, config)
})
}
Expand Down
83 changes: 70 additions & 13 deletions src/define_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,83 @@
* file that was distributed with this source code.
*/

import { configProvider } from '@adonisjs/core'
import { RuntimeException } from '@poppinss/utils'
import type { ConfigProvider } from '@adonisjs/core/types'

import loadersList from './loaders/main.js'
import formattersList from './formatters/main.js'
import type { I18nConfig, I18nServiceConfig } from './types/main.js'
import type {
LoaderFactory,
BaseI18nConfig,
FormatterFactory,
I18nManagerConfig,
FsLoaderOptions,
} from './types/main.js'

/**
* Define i18n config
* Config helper to define i18n config
*/
export function defineConfig(config: Partial<I18nServiceConfig>): I18nConfig {
export function defineConfig(
config: Partial<BaseI18nConfig> & {
formatter: FormatterFactory | ConfigProvider<FormatterFactory>
loaders: (ConfigProvider<LoaderFactory> | LoaderFactory)[]
}
): ConfigProvider<I18nManagerConfig> {
if (!config.formatter) {
throw new RuntimeException('Cannot configure i18n manager. Missing property "formatter"')
}

return {
defaultLocale: 'en',
...config,
formatter: (i18Config) => formattersList.create(config.formatter!, i18Config),
loaders: (config.loaders || []).map((loaderConfig) => {
return (i18nConfig) => loadersList.create(loaderConfig.driver, loaderConfig, i18nConfig)
}),
} satisfies I18nConfig
const { formatter, loaders, ...rest } = config

return configProvider.create(async (app) => {
/**
* Resolving formatter
*/
const resolvedFormatter =
typeof formatter === 'function' ? formatter : await formatter.resolver(app)

/**
* Resolving loaders. Each loader can be a factory or a
* config provider.
*/
const resolvedLoaders = await Promise.all(
loaders.map((loader) => {
return typeof loader === 'function' ? loader : loader.resolver(app)
})
)

return {
defaultLocale: 'en',
formatter: resolvedFormatter,
loaders: resolvedLoaders,
...rest,
} satisfies I18nManagerConfig
})
}

/**
* Config helper to configure a formatter for i18n
*/
export const formatters: {
icu: () => ConfigProvider<FormatterFactory>
} = {
icu() {
return configProvider.create(async () => {
const { IcuFormatter } = await import('../src/messages_formatters/icu.js')
return () => new IcuFormatter()
})
},
}

/**
* Config helper to configure loaders for i18n
*/
export const loaders: {
fs: (config: FsLoaderOptions) => ConfigProvider<LoaderFactory>
} = {
fs(config) {
return configProvider.create(async () => {
const { FsLoader } = await import('../src/loaders/fs.js')
return () => new FsLoader(config)
})
},
}
50 changes: 0 additions & 50 deletions src/formatters/main.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/i18n_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import Negotiator from 'negotiator'
import type { Emitter } from '@adonisjs/core/events'
import type {
I18nConfig,
I18nManagerConfig,
TranslationsFormatterContract,
MissingTranslationEventPayload,
} from './types/main.js'
Expand All @@ -22,7 +22,7 @@ export class I18nManager {
/**
* i18n config
*/
#config: I18nConfig
#config: I18nManagerConfig

/**
* Reference to the emitter for emitting events
Expand Down Expand Up @@ -71,7 +71,7 @@ export class I18nManager {

constructor(
emitter: Emitter<{ 'i18n:missing:translation': MissingTranslationEventPayload } & any>,
config: I18nConfig
config: I18nManagerConfig
) {
this.#config = config
this.#emitter = emitter
Expand Down
File renamed without changes.
54 changes: 0 additions & 54 deletions src/loaders/main.ts

This file was deleted.

File renamed without changes.
21 changes: 0 additions & 21 deletions src/types/extended.ts

This file was deleted.

48 changes: 16 additions & 32 deletions src/types/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
* file that was distributed with this source code.
*/

import type { FsLoader } from '../loaders/fs_loader.js'
import type { IcuFormatter } from '../formatters/icu_messages_formatter.js'

/**
* Options for formatting a numeric value. We override loose
* types from "Intl.NumberFormatOptions".
Expand Down Expand Up @@ -84,25 +81,11 @@ export type FsLoaderOptions = {
location: string | URL
}

/**
* Collection of loaders
*/
export interface TranslationsLoadersList {
fs: (config: FsLoaderOptions, i18nConfig: I18nConfig) => FsLoader
}

/**
* Collection of formatters
*/
export interface TranslationsFormattersList {
icu: (i18nConfig: I18nConfig) => IcuFormatter
}

/**
* Base config shared between i18n config and i18n service
* config
*/
type BaseI18nConfig = {
export type BaseI18nConfig = {
/**
* Default locale for the application. This locale is
* used when request locale is not supported by the
Expand All @@ -129,30 +112,31 @@ type BaseI18nConfig = {
fallback?: (identifier: string, locale: string) => string
}

/**
* Formatter factory is responsible for returning a
* formatter
*/
export type FormatterFactory = (i18nConfig: I18nManagerConfig) => TranslationsFormatterContract

/**
* Loader factory is responsible for returning a
* loader
*/
export type LoaderFactory = (i18nConfig: I18nManagerConfig) => TranslationsLoaderContract

/**
* Config for the package
*/
export interface I18nConfig extends BaseI18nConfig {
export interface I18nManagerConfig extends BaseI18nConfig {
/**
* Translations format to use
*/
formatter: (i18nConfig: I18nConfig) => TranslationsFormatterContract
formatter: FormatterFactory

/**
* Configured loaders for loading translations
*/
loaders: ((i18nConfig: I18nConfig) => TranslationsLoaderContract)[]
}

/**
* The service config auto resolves the formatter and loaders
* lazily using their unique names
*/
export interface I18nServiceConfig extends BaseI18nConfig {
formatter: keyof TranslationsFormattersList
loaders: {
[K in keyof TranslationsLoadersList]: Parameters<TranslationsLoadersList[K]>[0] & { driver: K }
}[keyof TranslationsLoadersList][]
loaders: LoaderFactory[]
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/configure.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ test.group('Configure', (group) => {
'app/middleware/detect_user_locale_middleware.ts',
`export default class DetectUserLocaleMiddleware`
)
}).timeout(10000)
}).timeout(60 * 1000)
})
Loading

0 comments on commit 377daaa

Please sign in to comment.