Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create instanceService #733

Merged
merged 14 commits into from
Jun 7, 2022
Merged
1 change: 1 addition & 0 deletions src/controller/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class SettingsController
id: SETTING_ID!,
value: next,
render(value) {
/* istanbul ignore next */
return <LocaleNotification key={next.id} locale={next.name} />;
},
};
Expand Down
11 changes: 5 additions & 6 deletions src/extensions/__tests__/folderTree.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import '@testing-library/jest-dom';
import molecule, { MoleculeProvider, Workbench } from 'mo';
import molecule, { create, Workbench } from 'mo';
import { cleanup, fireEvent, render } from '@testing-library/react';
import type { ITreeNodeItemProps } from 'mo/components';
import type { IEditorTab } from 'mo/model/workbench/editor';
Expand Down Expand Up @@ -35,11 +35,10 @@ describe('folderTree extension', () => {
afterEach(cleanup);

test('Execute the listener function of onUpdateFileName', () => {
const { getByRole } = render(
<MoleculeProvider>
<Workbench />
</MoleculeProvider>
);
const container = create({
extensions: [],
}).render(<Workbench />);
const { getByRole } = render(container);

molecule.folderTree.setState({ folderTree: { data: mockTreeData } });
expect(molecule.folderTree.getState().folderTree?.data).toEqual(
Expand Down
134 changes: 68 additions & 66 deletions src/i18n/__tests__/localeService.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import 'reflect-metadata';
import { container } from 'tsyringe';
import { expectLoggerErrorToBeCalled } from '@test/utils';
import { ILocale } from '../localization';
import { LocaleService } from '..';
import { BuiltInLocales, BuiltInDefault, ILocale } from '../localization';

describe('The Locale Service', () => {
const TestLocale = {
const TestLocale: ILocale = {
id: 'test',
source: new Map(),
name: 'test',
};

// LocaleService is support to add an object source but ILocale is banned
const TestEnLocale: ILocale = {
id: 'en',
name: 'English',
source: {
// @ts-ignore
'molecule.welcome': 'Welcome to Molecule',
'test.id': 'hello ${i}',
},
};

afterEach(() => {
localStorage.clear();
});
Expand All @@ -19,82 +31,72 @@ describe('The Locale Service', () => {
expect(localeService).not.toBeUndefined();
});

test('Reset the LocaleService', () => {
test('Initialize the locales with testLocale', () => {
const localeService = new LocaleService();
expect(localeService.getCurrentLocale()!.id).toBe(BuiltInDefault.id);
localeService.reset();
expect(localeService.getCurrentLocale()!.id).toBe(BuiltInDefault.id);
});
localeService.initialize([TestLocale], TestLocale.id);

test('Get default Locale', () => {
const localeService = new LocaleService();
const defaultLocale = localeService.getDefaultLocale();
expect(defaultLocale).toEqual(BuiltInDefault);
});
expect(localeService.getCurrentLocale()?.id).toEqual(TestLocale.id);
expect(localeService.getLocales().length).toBe(1);

test('Get default Locales', () => {
const localeService = new LocaleService();
const defaultLocale = localeService.getDefaultLocales();
expect(defaultLocale).toEqual(BuiltInLocales);
localeService.reset();
expectLoggerErrorToBeCalled(() => {
// @ts-ignore
localeService.initialize([TestEnLocale, TestLocale]);
});
});

test('The size of Built-in Locales should be 3', () => {
test('Reset the LocaleService', () => {
const localeService = new LocaleService();
const locales = localeService.getLocales();
expect(locales.length).toBe(3);
});
expect(localeService.getCurrentLocale()).toBeUndefined();

test('Initialize the locales', () => {
const localeService = new LocaleService();
localeService.initialize([TestLocale]);
expect(localeService.getCurrentLocale()!.id).toEqual(
localeService.getDefaultLocale().id
);
expect(localeService.getLocales().length).toBe(4);
localeService.initialize([], 'test');
expect(localeService.getCurrentLocale()!.id).toEqual(BuiltInDefault.id);
// Clear the cached locale value
localStorage.clear();
localeService.initialize([], 'test');
expect(localeService.getCurrentLocale()!.id).toEqual('test');
localeService.initialize([]);
// Get from the localStorage cache
expect(localeService.getCurrentLocale()!.id).toEqual('test');
localeService.initialize([TestLocale], TestLocale.id);
expect(localeService.getCurrentLocale()).toEqual(TestLocale);

localeService.reset();
expect(localeService.getCurrentLocale()).toBeUndefined();
});

test('Get/Set current locale', () => {
const localeService = new LocaleService();
(localeService as any)._current = undefined;
expect(localeService.getCurrentLocale()).toBe(BuiltInDefault);
localeService.addLocales([TestLocale]);
localeService.setCurrentLocale(TestLocale.id);
expect(localeService.getCurrentLocale()!.id).toEqual(TestLocale.id);
expect(localeService.getCurrentLocale()).toBeUndefined();

localeService.initialize([TestLocale, TestEnLocale], TestLocale.id);

expect(localeService.getCurrentLocale()?.id).toEqual(TestLocale.id);

localeService.setCurrentLocale(TestEnLocale.id);
expect(localeService.getCurrentLocale()?.id).toEqual(TestEnLocale.id);
// set an unknow locale will fail
expect(localeService.setCurrentLocale('unknown')).toEqual(false);
});

test('Add locales', () => {
const localeService = new LocaleService();
expect(localeService.getLocales().length).toBe(3);
expect(localeService.getLocales().length).toBe(0);

localeService.addLocales([TestLocale]);
expect(localeService.getLocales().length).toBe(4);
expect(localeService.getLocales().length).toBe(1);

localeService.addLocales([]);
expect(localeService.getLocales().length).toBe(4);
expect(localeService.getLocales().length).toBe(1);

// Add an existed locale
localeService.addLocales([TestLocale]);
expect(localeService.getLocales().length).toBe(4);
expect(localeService.getLocales().length).toBe(1);
});

test('Add an locale inherit the en', () => {
const localeService = new LocaleService();
localeService.initialize([TestEnLocale], TestEnLocale.id);

expect(TestLocale.source.size).toBe(0);
(TestLocale as ILocale).inherit = 'en';
TestLocale.inherit = 'en';
localeService.addLocales([TestLocale]);
expect(localeService.getLocale(TestLocale.id)?.source.size).not.toBe(0);

// Inherit an not exist locale
localeService.removeLocale(TestLocale.id);
(TestLocale as ILocale).inherit = 'unknown';
TestLocale.inherit = 'unknown';
localeService.addLocales([TestLocale]);
expect(localeService.getLocale(TestLocale.id)?.source.size).toBe(0);
});
Expand All @@ -110,38 +112,47 @@ describe('The Locale Service', () => {

test('Remove a locale', () => {
const localeService = new LocaleService();
localeService.addLocales([TestLocale]);
localeService.initialize([TestLocale, TestEnLocale], TestLocale.id);
expect(localeService.getLocale(TestLocale.id)?.id).toEqual(
TestLocale.id
);
localeService.removeLocale(TestLocale.id);

const removedLocale = localeService.removeLocale(TestLocale.id);
expect(localeService.getLocale(TestLocale.id)).toBeUndefined();
expect(removedLocale).toEqual(TestLocale);

localeService.addLocales([TestLocale]);
localeService.setCurrentLocale(TestLocale.id);

//Remove the current locale
expect(localeService.getCurrentLocale()!.id).toEqual(TestLocale.id);
expect(localeService.getCurrentLocale()?.id).toEqual(TestLocale.id);
localeService.removeLocale(TestLocale.id);
expect(localeService.getCurrentLocale()!.id).toEqual(
localeService.getDefaultLocale().id
);
expect(localeService.getCurrentLocale()!.id).toEqual(TestEnLocale.id);

// Remove an undefined
expect(localeService.removeLocale(TestLocale.id));

expect(localeService.getLocales().length).toBe(1);
// The last one couldn't be removed
expect(localeService.removeLocale(TestEnLocale.id)).toBeFalsy();
});

test('Listen to the current locale change event', () => {
const target = 'zh-CN';
const localeService = new LocaleService();
const fn = jest.fn();
localeService.onChange(fn);
localeService.setCurrentLocale(target);

localeService.initialize([TestLocale, TestEnLocale], TestLocale.id);
localeService.setCurrentLocale(TestEnLocale.id);

expect(fn).toBeCalledTimes(1);
expect(localeService.getCurrentLocale()!.id).toEqual(target);
expect(localeService.getCurrentLocale()!.id).toEqual(TestEnLocale.id);
});

test('Localize the source key', () => {
const localeService = new LocaleService();

localeService.initialize([TestLocale, TestEnLocale], TestEnLocale.id);
let res = localeService.localize('test');
expect(res).toEqual('');

Expand All @@ -154,19 +165,10 @@ describe('The Locale Service', () => {
res = localeService.localize('molecule.welcome', 'default');
expect(res).toEqual('Welcome to Molecule');

const map = new Map();
map.set('test.id', 'hello ${i}');
const mockData = {
id: 'mock',
name: 'mock',
source: map,
};
localeService.addLocales([mockData]);
localeService.setCurrentLocale(mockData.id);
res = localeService.localize('test.id', '', 'world');
expect(res).toEqual('hello world');

(localeService as any)._current = null;
localeService.setCurrentLocale(TestLocale.id);
res = localeService.localize('molecule.welcome', 'default');
expect(res).toEqual('default');
});
Expand Down
64 changes: 18 additions & 46 deletions src/i18n/localeService.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import { APP_PREFIX } from 'mo/common/const';
import {
ILocale,
LocalizationEvent,
BuiltInLocales,
BuiltInDefault,
} from 'mo/i18n/localization';
import logger from 'mo/common/logger';
import { ILocale, LocalizationEvent } from 'mo/i18n/localization';

import { Component } from 'mo/react';
import { singleton } from 'tsyringe';

export interface ILocaleService {
/**
* Initialize the locales data, and the default current locale language,
* this method first uses the cached `locale` in localStorage, then use the
* localeId argument, if both the values are null, finally apply the built-in BuiltInZhCN
* Initialize the locales data, and the current locale language,
* @param locales
* @param localeId
*/
initialize(locales: ILocale[], localeId?: string): void;
initialize(locales: ILocale[], localeId: string): void;
/**
* Set the current locale language by id
* @param id
Expand All @@ -36,14 +30,6 @@ export interface ILocaleService {
* @param id
*/
getLocale(id: string): ILocale | undefined;
/**
* Get the default locale
*/
getDefaultLocale(): ILocale;
/**
* Get the default locales;
*/
getDefaultLocales(): ILocale[];
/**
* Add multiple local languages
* @param locales
Expand Down Expand Up @@ -91,15 +77,11 @@ export class LocaleService extends Component implements ILocaleService {
state = {};
private static LOCALIZE_REPLACED_WORD = '${i}';

private _locales: Map<string, ILocale> = new Map();
private _locales = new Map<string, ILocale>();
private _current: ILocale | undefined;

constructor() {
super();
/**
* TODO: It will then be removed accordingly
*/
this.initialize(BuiltInLocales);
}

public reset(): void {
Expand All @@ -108,37 +90,21 @@ export class LocaleService extends Component implements ILocaleService {
this._locales.clear();
}

public getDefaultLocale(): ILocale {
return Object.assign({}, BuiltInDefault);
}

public getDefaultLocales(): ILocale[] {
return BuiltInLocales.concat();
}

public getLocales(): ILocale[] {
return Array.from(this._locales.values());
}

public initialize(locales: ILocale[], localeId?: string) {
public initialize(locales: ILocale[], localeId: string) {
this.addLocales(locales);
let finalLocale = BuiltInDefault!.id;
if (localeId) {
finalLocale = localeId;
}
const cachedLocaleId = localStorage.getItem(STORE_KEY);
if (cachedLocaleId) {
finalLocale = cachedLocaleId;
if (this._locales.get(localeId)) {
this._current = this._locales.get(localeId);
} else {
logger.error(`Cannot initialize the locale with ${localeId}`);
}

this.setCurrentLocale(finalLocale);
}

public getCurrentLocale(): ILocale | undefined {
return (
(this._current && Object.assign({}, this._current)) ||
BuiltInDefault
);
return this._current && Object.assign({}, this._current);
}

public getLocale(id: string | null): ILocale | undefined {
Expand All @@ -149,8 +115,14 @@ export class LocaleService extends Component implements ILocaleService {
public removeLocale(id: string): ILocale | undefined {
const locale = this._locales.get(id);
if (locale !== undefined) {
if (this._locales.size === 1) {
logger.error(
"You can't remove this Locale because there must have one locale at least"
);
return undefined;
}
if (this._current && this._current.id === locale.id) {
this._current = this.getDefaultLocale();
this._current = this._locales.values().next().value;
}
this._locales.delete(id);
return locale;
Expand Down
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as molecule from './molecule.api';
import * as moleculeAPI from './molecule.api';

export { MoleculeProvider } from 'mo/provider';
export type { IMoleculeProps } from 'mo/provider';
import { molecule } from './provider/create';

export { Workbench } from 'mo/workbench/workbench';
export { molecule };
export { create } from 'mo/provider';

export default molecule;
// TODO: put API into moleucle temporarily, should consider it
export default Object.assign(molecule, moleculeAPI);
Loading