Skip to content
This repository was archived by the owner on Feb 6, 2024. It is now read-only.

Commit bdc79b9

Browse files
Merge pull request #1110 from deckgo/lang
feat: toggle lang and detection
2 parents f039a77 + 975cad4 commit bdc79b9

File tree

7 files changed

+150
-22
lines changed

7 files changed

+150
-22
lines changed

studio/scripts/i18n.types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const generate = async () => {
1616
};
1717
});
1818

19-
const lang = `lang: 'en';`;
19+
const lang = `lang: Languages;`;
2020

2121
const main = `\n\ninterface I18n {${lang}${data.map((i) => `${i.key}: ${i.name};`).join('')}}`;
2222
const interfaces = data.map((i) => `\n\ninterface ${i.name} {${i.properties.join('')}}`).join('');

studio/src/app/app-root.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {OfflineService} from './services/editor/offline/offline.service';
1313
import {NavDirection, NavParams} from './stores/nav.store';
1414
import {ColorService} from './services/color/color.service';
1515
import {SettingsService} from './services/settings/settings.service';
16+
import {LangService} from './services/lang/lang.service';
1617

1718
@Component({
1819
tag: 'app-root',
@@ -27,6 +28,7 @@ export class AppRoot {
2728
private readonly themeService: ThemeService;
2829
private readonly colorService: ColorService;
2930
private readonly settingsService: SettingsService;
31+
private readonly langService: LangService;
3032

3133
@State()
3234
private loading: boolean = true;
@@ -43,6 +45,7 @@ export class AppRoot {
4345
this.themeService = ThemeService.getInstance();
4446
this.colorService = ColorService.getInstance();
4547
this.settingsService = SettingsService.getInstance();
48+
this.langService = LangService.getInstance();
4649
}
4750

4851
async componentWillLoad() {
@@ -53,6 +56,7 @@ export class AppRoot {
5356
this.themeService.initDarkModePreference(),
5457
this.colorService.init(),
5558
this.settingsService.init(),
59+
this.langService.init(),
5660
];
5761

5862
await Promise.all(promises);

studio/src/app/definitions/i18.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ interface I18nPoll {
487487
}
488488

489489
interface I18n {
490-
lang: 'en';
490+
lang: Languages;
491491
core: I18nCore;
492492
nav: I18nNav;
493493
menu: I18nMenu;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type Languages = 'en' | 'es';

studio/src/app/pages/core/settings/app-customization/app-customization.tsx

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Component, Fragment, h} from '@stencil/core';
1+
import {Component, h} from '@stencil/core';
22

33
import themeStore from '../../../../stores/theme.store';
44
import settingsStore from '../../../../stores/settings.store';
@@ -29,6 +29,10 @@ export class AppCustomization {
2929
settingsStore.state.editMode = settingsStore.state.editMode === 'css' ? 'properties' : 'css';
3030
}
3131

32+
private toggleLang($event: CustomEvent) {
33+
i18n.state.lang = $event.detail.value;
34+
}
35+
3236
render() {
3337
return [
3438
<app-navigation></app-navigation>,
@@ -39,6 +43,8 @@ export class AppCustomization {
3943
<ion-list class="inputs-list dark-light-list">
4044
{this.renderDarkLightToggle()}
4145

46+
{this.renderLang()}
47+
4248
{this.renderEditMode()}
4349
</ion-list>
4450
</main>
@@ -57,25 +63,40 @@ export class AppCustomization {
5763
);
5864
}
5965

66+
private renderLang() {
67+
return (
68+
<ion-item class="select">
69+
<ion-label>{i18n.state.editor.language}</ion-label>
70+
<ion-select
71+
slot="end"
72+
value={i18n.state.lang}
73+
onIonChange={($event: CustomEvent) => this.toggleLang($event)}
74+
interface="popover"
75+
mode="md"
76+
class="ion-padding-start ion-padding-end">
77+
<ion-select-option value="en">English</ion-select-option>
78+
<ion-select-option value="es">Español</ion-select-option>
79+
</ion-select>
80+
</ion-item>
81+
);
82+
}
83+
6084
private renderEditMode() {
6185
return (
62-
<Fragment>
63-
<ion-item-divider class="ion-padding-top">
64-
<ion-label>{i18n.state.settings.edit_mode}</ion-label>
65-
</ion-item-divider>
66-
67-
<ion-radio-group value={this.editMode} onIonChange={() => this.toggleEditMode()}>
68-
<ion-item>
69-
<ion-radio value="properties" mode="md" slot="start"></ion-radio>
70-
<ion-label>{i18n.state.settings.properties}</ion-label>
71-
</ion-item>
72-
73-
<ion-item>
74-
<ion-radio value="css" mode="md" slot="start"></ion-radio>
75-
<ion-label>CSS</ion-label>
76-
</ion-item>
77-
</ion-radio-group>
78-
</Fragment>
86+
<ion-item>
87+
<ion-label>{i18n.state.settings.edit_mode}</ion-label>
88+
89+
<ion-select
90+
slot="end"
91+
value={this.editMode}
92+
onIonChange={() => this.toggleEditMode()}
93+
interface="popover"
94+
mode="md"
95+
class="ion-padding-start ion-padding-end">
96+
<ion-select-option value="properties">{i18n.state.settings.properties}</ion-select-option>
97+
<ion-select-option value="css">CSS</ion-select-option>
98+
</ion-select>
99+
</ion-item>
79100
);
80101
}
81102
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import i18n from '../../stores/i18n.store';
2+
3+
import {get} from 'idb-keyval';
4+
5+
export class LangService {
6+
private static instance: LangService;
7+
8+
private constructor() {
9+
// Private constructor, singleton
10+
}
11+
12+
static getInstance() {
13+
if (!LangService.instance) {
14+
LangService.instance = new LangService();
15+
}
16+
return LangService.instance;
17+
}
18+
19+
async init() {
20+
try {
21+
const lang: Languages | null = await get<Languages>('deckdeckgo_lang');
22+
23+
if (lang) {
24+
i18n.state.lang = lang;
25+
return;
26+
}
27+
28+
this.initDefaultLang();
29+
} catch (err) {
30+
console.warn(`Couldn't find lang. Proceeding with default`);
31+
}
32+
}
33+
34+
private initDefaultLang() {
35+
const browserLang: string | undefined = this.getBrowserLang();
36+
i18n.state.lang = /(es|en)/gi.test(browserLang) ? (browserLang as Languages) : 'en';
37+
}
38+
39+
/**
40+
* From ngx-translate
41+
* https://github.com/ngx-translate/core/blob/efcb4f43a645d9ac630aae8e50b60cc883e675fd/projects/ngx-translate/core/src/lib/translate.service.ts
42+
* @private
43+
*/
44+
private getBrowserLang(): string | undefined {
45+
if (typeof window === 'undefined' || typeof window.navigator === 'undefined') {
46+
return undefined;
47+
}
48+
49+
let browserLang: string | null = window.navigator.languages ? window.navigator.languages[0] : null;
50+
// @ts-ignore
51+
browserLang = browserLang || window.navigator.language || window.navigator.browserLanguage || window.navigator.userLanguage;
52+
53+
if (typeof browserLang === 'undefined') {
54+
return undefined;
55+
}
56+
57+
if (browserLang.indexOf('-') !== -1) {
58+
browserLang = browserLang.split('-')[0];
59+
}
60+
61+
if (browserLang.indexOf('_') !== -1) {
62+
browserLang = browserLang.split('_')[0];
63+
}
64+
65+
return browserLang;
66+
}
67+
}
Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,45 @@
11
import {createStore} from '@stencil/store';
22

33
import en from '../../assets/i18n/en.json';
4+
import {set} from 'idb-keyval';
45

5-
const {state} = createStore<I18n>({
6-
lang: en,
6+
const {state, onChange} = createStore<I18n>({
7+
lang: 'en',
78
...(en as Partial<I18n>),
89
} as I18n);
910

11+
const esI18n = async (): Promise<I18n> => {
12+
return {
13+
lang: 'es',
14+
...(await import(`../../assets/i18n/es.json`)),
15+
};
16+
};
17+
18+
const enI18n = (): I18n => {
19+
return {
20+
lang: 'en',
21+
...(en as Partial<I18n>),
22+
} as I18n;
23+
};
24+
25+
onChange('lang', async (lang: Languages) => {
26+
let bundle: I18n;
27+
28+
switch (lang) {
29+
case 'es':
30+
bundle = await esI18n();
31+
break;
32+
default:
33+
bundle = enI18n();
34+
}
35+
36+
Object.assign(state, bundle);
37+
});
38+
39+
onChange('lang', (lang: Languages) => {
40+
set('deckdeckgo_lang', lang).catch((err) => {
41+
console.error('Failed to update IDB with new language', err);
42+
});
43+
});
44+
1045
export default {state};

0 commit comments

Comments
 (0)