Skip to content

Commit

Permalink
feat: prepare for server components (and server-only rendering) (#3226)
Browse files Browse the repository at this point in the history
  • Loading branch information
stepan662 authored Aug 11, 2023
1 parent 38d4c0a commit 358ed9c
Show file tree
Hide file tree
Showing 35 changed files with 338 additions and 145 deletions.
7 changes: 3 additions & 4 deletions packages/core/src/Controller/Cache/Cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import {
TranslationsFlat,
TranslationValue,
TreeTranslationsData,
BackendGetRecord,
BackendGetDevRecord,
BackendGetRecordInternal,
} from '../../types';
import { getFallbackArray, unique } from '../../helpers';
import { EventEmitterInstance } from '../Events/EventEmitter';
Expand All @@ -30,8 +29,8 @@ type StateCache = Map<string, CacheRecord>;

export function Cache(
onCacheChange: EventEmitterInstance<CacheDescriptorWithKey>,
backendGetRecord: BackendGetRecord,
backendGetDevRecord: BackendGetDevRecord,
backendGetRecord: BackendGetRecordInternal,
backendGetDevRecord: BackendGetRecordInternal,
withDefaultNs: (descriptor: CacheDescriptor) => CacheDescriptorInternal,
isInitialLoading: () => boolean,
fetchingObserver: ValueObserverInstance<boolean>,
Expand Down
11 changes: 10 additions & 1 deletion packages/core/src/Controller/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TFnType,
NsType,
KeyAndNamespacesInternal,
TranslationDescriptor,
} from '../types';
import { Cache } from './Cache/Cache';
import { getFallbackArray } from '../helpers';
Expand Down Expand Up @@ -44,7 +45,8 @@ export function Controller({ options }: StateServiceProps) {
state.getAvailableLanguages,
getTranslationNs,
getTranslation,
changeTranslation
changeTranslation,
onPermanentChange
);

const cache = Cache(
Expand Down Expand Up @@ -105,6 +107,13 @@ export function Controller({ options }: StateServiceProps) {
};
}

function onPermanentChange(props: TranslationDescriptor) {
events.onPermanentChange.emit({
key: props.key,
namespace: props.namespace,
});
}

function init(options: Partial<TolgeeOptions>) {
state.init(options);
cache.addStaticData(state.getInitialOptions().staticData);
Expand Down
9 changes: 8 additions & 1 deletion packages/core/src/Controller/Events/Events.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { EventEmitter } from './EventEmitter';
import { EventEmitterSelective } from './EventEmitterSelective';
import { CacheDescriptorWithKey, TolgeeOn } from '../../types';
import {
CacheDescriptorWithKey,
TolgeeOn,
TranslationDescriptor,
} from '../../types';

export function Events(
getFallbackNs: () => string[],
Expand All @@ -21,6 +25,7 @@ export function Events(
onRunningChange: EventEmitter<boolean>(isActive),
onCacheChange: EventEmitter<CacheDescriptorWithKey>(isActive),
onUpdate: EventEmitterSelective(isActive, getFallbackNs, getDefaultNs),
onPermanentChange: EventEmitter<TranslationDescriptor>(isActive),
setEmitterActive(active: boolean) {
emitterActive = active;
},
Expand All @@ -42,6 +47,8 @@ export function Events(
return self.onCacheChange.listen(handler as any);
case 'update':
return self.onUpdate.listen(handler as any);
case 'permanentChange':
return self.onPermanentChange.listen(handler as any);
}
}) as TolgeeOn,
});
Expand Down
29 changes: 22 additions & 7 deletions packages/core/src/Controller/Plugins/Plugins.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getErrorMessage, isPromise, valueOrPromise } from '../../helpers';
import {
BackendDevMiddleware,
BackendGetRecord,
BackendMiddleware,
FormatterMiddleware,
ObserverMiddleware,
Expand All @@ -22,6 +21,8 @@ import {
TolgeeOptionsInternal,
FormatErrorHandler,
FindPositionsInterface,
BackendGetRecordInternal,
TranslationDescriptor,
} from '../../types';
import { DEFAULT_FORMAT_ERROR } from '../State/initState';

Expand All @@ -31,7 +32,8 @@ export function Plugins(
getAvailableLanguages: () => string[] | undefined,
getTranslationNs: (props: KeyAndNamespacesInternal) => string[],
getTranslation: (props: KeyAndNamespacesInternal) => string | undefined,
changeTranslation: ChangeTranslationInterface
changeTranslation: ChangeTranslationInterface,
onPermanentChange: (props: TranslationDescriptor) => void
) {
const plugins = {
ui: undefined as UiMiddleware | undefined,
Expand Down Expand Up @@ -81,6 +83,10 @@ export function Plugins(
});
}

function getCommonProps() {
return { fetch: getInitialOptions().fetch };
}

function setObserver(observer: ObserverMiddleware | undefined) {
instances.observer = observer?.();
}
Expand Down Expand Up @@ -126,6 +132,7 @@ export function Plugins(

return instances.languageDetector.getLanguage({
availableLanguages,
...getCommonProps(),
});
}

Expand Down Expand Up @@ -168,6 +175,7 @@ export function Plugins(
highlight: self.highlight,
changeTranslation,
findPositions,
onPermanentChange,
});

instances.observer?.run({
Expand All @@ -189,7 +197,9 @@ export function Plugins(

getInitialLanguage() {
const availableLanguages = getAvailableLanguages();
const languageOrPromise = instances.languageStorage?.getLanguage();
const languageOrPromise = instances.languageStorage?.getLanguage(
getCommonProps()
);

return valueOrPromise(languageOrPromise, (language) => {
if (
Expand All @@ -203,7 +213,7 @@ export function Plugins(
},

setStoredLanguage(language: string) {
instances.languageStorage?.setLanguage(language);
instances.languageStorage?.setLanguage(language, getCommonProps());
},

getDevBackend() {
Expand All @@ -212,7 +222,11 @@ export function Plugins(

getBackendRecord: (({ language, namespace }) => {
for (const backend of instances.backends) {
const data = backend.getRecord({ language, namespace });
const data = backend.getRecord({
language,
namespace,
...getCommonProps(),
});
if (isPromise(data)) {
return data?.catch((e) => {
// eslint-disable-next-line no-console
Expand All @@ -225,7 +239,7 @@ export function Plugins(
}
}
return undefined;
}) as BackendGetRecord,
}) as BackendGetRecordInternal,

getBackendDevRecord: (({ language, namespace }) => {
const { apiKey, apiUrl, projectId } = getInitialOptions();
Expand All @@ -235,8 +249,9 @@ export function Plugins(
projectId,
language,
namespace,
...getCommonProps(),
});
}) as BackendGetRecord,
}) as BackendGetRecordInternal,

getLanguageDetector() {
return instances.languageDetector;
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/Controller/State/initState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
FallbackLanguageOption,
TreeTranslationsData,
OnFormatError,
FetchFn,
} from '../../types';
import { sanitizeUrl } from '../../helpers';
import {
Expand Down Expand Up @@ -97,6 +98,11 @@ export type TolgeeOptionsInternal = {
* Define what to display in case of formatting error. (Default: 'invalid')
*/
onFormatError: OnFormatError;

/**
* Define custom fetch function, used for fetching the translations
*/
fetch: FetchFn;
};

export type TolgeeOptions = Partial<
Expand All @@ -120,6 +126,7 @@ const defaultValues: TolgeeOptionsInternal = {
observerType: 'invisible',
onFormatError: DEFAULT_FORMAT_ERROR,
apiUrl: DEFAULT_API_URL,
fetch: (input, options) => fetch(input, options),
};

export const combineOptions = <T extends TolgeeOptions>(
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/Controller/State/observerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ export type ObserverOptionsInternal = {
* Html elements which will pass click listener to their parent (default: ['option', 'optgroup'])
*/
passToParent: (keyof HTMLElementTagNameMap)[] | ((node: Element) => boolean);

/**
* Encodes full key info into the invisble characters (default: false)
*/
fullKeyEncode: boolean;
};

export type ObserverOptions = Partial<ObserverOptionsInternal>;
Expand All @@ -63,4 +68,5 @@ export const defaultObserverOptions: ObserverOptionsInternal = {
inputPrefix: '%-%tolgee:',
inputSuffix: '%-%',
passToParent: ['option', 'optgroup'],
fullKeyEncode: false,
};
18 changes: 17 additions & 1 deletion packages/core/src/types/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export type TolgeeEvent =
| 'initialLoad'
| 'running'
| 'cache'
| 'update';
| 'update'
| 'permanentChange';

export interface EventType {
language: string;
Expand All @@ -38,6 +39,7 @@ export interface EventType {
running: boolean;
cache: CacheDescriptorWithKey;
update: void;
permanentChange: CacheDescriptorWithKey;
}

export type TolgeeOn<E extends keyof EventType = keyof EventType> = {
Expand Down Expand Up @@ -81,5 +83,19 @@ export type TolgeeOn<E extends keyof EventType = keyof EventType> = {
* Emitted when cache changes.
*/
(event: 'cache', handler: Listener<CacheDescriptorWithKey>): Subscription;

/**
* Translation was changed or created via dev tools
*/
(
event: 'permanentChange',
handler: Listener<CacheDescriptorWithKey>
): Subscription;

(event: E, handler: unknown): Subscription;
};

export type TranslationDescriptor = {
key: string;
namespace: string | undefined;
};
5 changes: 5 additions & 0 deletions packages/core/src/types/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,8 @@ export type KeyAndNamespacesInternal = Pick<
TranslatePropsInternal,
'key' | 'ns' | 'language'
>;

export type FetchFn = (
input: string | URL,
init?: RequestInit | undefined
) => Promise<Response>;
20 changes: 17 additions & 3 deletions packages/core/src/types/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
import { ChangeTranslationInterface, TreeTranslationsData } from './cache';
import {
FetchFn,
NsFallback,
NsType,
TranslateParams,
TranslatePropsInternal,
} from './general';
import type { ObserverOptionsInternal } from '../Controller/State/observerOptions';
import { TolgeeInstance } from '../TolgeeCore';
import { TranslationDescriptor } from './events';

export type BackendDevProps = {
apiUrl?: string;
apiKey?: string;
projectId?: number | string;
};

export type CommonProps = {
fetch: FetchFn;
};

export type BackendGetRecordProps = {
language: string;
namespace?: string;
};

export type BackendGetRecord = (
data: BackendGetRecordProps
data: BackendGetRecordProps & CommonProps
) => Promise<TreeTranslationsData | undefined> | undefined;

export interface BackendMiddleware {
getRecord: BackendGetRecord;
}

export type BackendGetDevRecord = (
data: BackendGetRecordProps & CommonProps & BackendDevProps
) => Promise<TreeTranslationsData | undefined> | undefined;

export type BackendGetRecordInternal = (
data: BackendGetRecordProps & BackendDevProps
) => Promise<TreeTranslationsData | undefined> | undefined;

Expand Down Expand Up @@ -82,6 +92,7 @@ export type ObserverMiddleware = () => {

export type LanguageDetectorProps = {
availableLanguages: string[];
fetch: FetchFn;
};

export type LanguageDetectorMiddleware = {
Expand All @@ -91,8 +102,10 @@ export type LanguageDetectorMiddleware = {
};

export type LanguageStorageMiddleware = {
getLanguage: () => string | undefined | Promise<string | undefined>;
setLanguage: (language: string) => void | Promise<void>;
getLanguage: (
props: CommonProps
) => string | undefined | Promise<string | undefined>;
setLanguage: (language: string, props: CommonProps) => void | Promise<void>;
};

export type DevCredentials =
Expand Down Expand Up @@ -150,6 +163,7 @@ export type UiProps = {
highlight: HighlightInterface;
findPositions: (key?: string | undefined, ns?: NsFallback) => KeyPosition[];
changeTranslation: ChangeTranslationInterface;
onPermanentChange: (props: TranslationDescriptor) => void;
};

export type UiKeyOption = {
Expand Down
Loading

0 comments on commit 358ed9c

Please sign in to comment.