Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions packages/i18n/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@serverlessworkflow/i18n",
"version": "1.0.0",
"files": [
"dist",
"src"
],
"type": "module",
"scripts": {
"clean": "rimraf ./dist",
"build": "pnpm clean && tsc -p tsconfig.json",
"build:prod": "pnpm run build"
},
"devDependencies": {
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"rimraf": "catalog:",
"typescript": "catalog:"
},
"peerDependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
}
}
19 changes: 19 additions & 0 deletions packages/i18n/src/api/I18nChannelApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export interface I18nChannelApi {
editorI18n_getLocale(): Promise<string>;
}
19 changes: 19 additions & 0 deletions packages/i18n/src/api/I18nEnvelopeApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export interface I18nEnvelopeApi {
editorI18n_localeChange(locale: string): void;
}
18 changes: 18 additions & 0 deletions packages/i18n/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export * from "./I18nChannelApi";
export * from "./I18nEnvelopeApi";
48 changes: 48 additions & 0 deletions packages/i18n/src/core/Dictionary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Wrapped } from "./Wrapped";

export interface I18nDefaults<D extends ReferenceDictionary<D>> {
locale: string;
dictionary: D;
}

export type I18nDictionaries<D extends ReferenceDictionary<D>> = Map<
string,
TranslatedDictionary<D>
>;

export type DictionaryInterpolation = (...args: Array<string | number>) => string;

export type ReferenceDictionary<D extends ReferenceDictionary<D>> = {
[K in keyof D]: D[K] extends string
? string
: D[K] extends (...args: any[]) => string
? DictionaryInterpolation
: D[K] extends Wrapped<string>
? Wrapped<string>
: D[K] extends Array<string | number | Wrapped<string>>
? Array<string | number | Wrapped<string>>
: D[K] extends Record<string, any>
? ReferenceDictionary<D[K]>
: never;
};

// Locales that aren't the default should implement this interface
export type TranslatedDictionary<D extends ReferenceDictionary<D>> = DeepOptional<D>;

type DeepOptional<D> = { [K in keyof D]?: DeepOptional<D[K]> };
61 changes: 61 additions & 0 deletions packages/i18n/src/core/I18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
I18nDefaults,
I18nDictionaries,
ReferenceDictionary,
TranslatedDictionary,
} from "./Dictionary";
import { immutableDeepMerge } from "./immutableDeepMerge";

export class I18n<D extends ReferenceDictionary<D>> {
private locale: string;
private dictionary!: D;

constructor(
private readonly defaults: I18nDefaults<D>,
private readonly dictionaries: I18nDictionaries<D>,
private readonly initialLocale = defaults.locale,
) {
this.locale = initialLocale;
this.updateDictionary();
}

public setLocale(locale: string): I18n<D> {
this.locale = locale;
this.updateDictionary();
return this;
}

private updateDictionary(): I18n<D> {
const selectedDictionary =
this.dictionaries.get(this.locale) ??
this.dictionaries.get(this.locale.split("-").shift()!) ??
{};

this.dictionary = immutableDeepMerge(this.defaults.dictionary, selectedDictionary) as D;
return this;
}

public getCurrent(): D {
return this.dictionary;
}

public getLocale(): string {
return this.locale;
}
}
26 changes: 26 additions & 0 deletions packages/i18n/src/core/Wrapped.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export interface Wrapped<Name> {
nameValue: Name;
}

export function wrapped<Name extends string>(wrappedName: Name): Wrapped<Name> {
return { nameValue: wrappedName };
}

export type ExtractWrappedComponentNames<Component> =
Component extends Wrapped<infer Name> ? Name : never;
51 changes: 51 additions & 0 deletions packages/i18n/src/core/immutableDeepMerge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { DictionaryInterpolation, ReferenceDictionary, TranslatedDictionary } from "./Dictionary";

function deepMerge<D extends ReferenceDictionary<D>>(
target: ReferenceDictionary<D>,
source: TranslatedDictionary<ReferenceDictionary<D>>,
): ReferenceDictionary<D> {
(Object.keys(source) as Array<Extract<keyof D, string>>).forEach((key) => {
const sourceValue = source[key];

if (!sourceValue) {
return;
}
if (typeof sourceValue === "string" || typeof sourceValue === "function") {
target[key] = sourceValue as ReferenceDictionary<D>[typeof key];
} else {
target[key] = deepMerge(
createObjectCopy(target[key] as ReferenceDictionary<D>),
sourceValue as TranslatedDictionary<ReferenceDictionary<D>>,
) as ReferenceDictionary<D>[typeof key];
}
});
return target;
}

export function immutableDeepMerge<D extends ReferenceDictionary<D>>(
target: ReferenceDictionary<D>,
source: TranslatedDictionary<ReferenceDictionary<D>>,
) {
const targetCopy = createObjectCopy(target);
return deepMerge(targetCopy, source);
}

function createObjectCopy<T extends Record<string, unknown>>(obj?: T) {
return Object.assign({} as T, obj);
}
19 changes: 19 additions & 0 deletions packages/i18n/src/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export * from "./I18n";
export * from "./Dictionary";
export * from "./Wrapped";
37 changes: 37 additions & 0 deletions packages/i18n/src/envelope/I18nService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export class I18nService {
constructor(private readonly onLocaleChangeSubscriptions: Array<(locale: string) => void> = []) {}

public executeOnLocaleChangeSubscriptions(locale: string) {
this.onLocaleChangeSubscriptions.forEach((onLocaleChange) => {
onLocaleChange?.(locale);
});
}

public subscribeToLocaleChange(onLocaleChange: (locale: string) => void) {
this.onLocaleChangeSubscriptions.push(onLocaleChange);
return onLocaleChange;
}

public unsubscribeToLocaleChange(onLocaleChange: (locale: string) => void) {
const index = this.onLocaleChangeSubscriptions.indexOf(onLocaleChange);
if (index > -1) {
this.onLocaleChangeSubscriptions.splice(index, 1);
}
}
}
17 changes: 17 additions & 0 deletions packages/i18n/src/envelope/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export * from "./I18nService";
24 changes: 24 additions & 0 deletions packages/i18n/src/react-components/I18nContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2021-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as React from "react";
import { ReferenceDictionary } from "../core";

export interface I18nContextType<D extends ReferenceDictionary<D>> {
locale: string;
setLocale: React.Dispatch<string>;
i18n: D;
}
Loading
Loading