mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-27 12:36:14 +01:00
i18n service and helpers
This commit is contained in:
parent
0e33ad9b0b
commit
2ab23c2c9e
5
src/_locales/en/messages.json
Normal file
5
src/_locales/en/messages.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"hello": {
|
||||||
|
"message": "hello"
|
||||||
|
}
|
||||||
|
}
|
5
src/_locales/es/messages.json
Normal file
5
src/_locales/es/messages.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"hello": {
|
||||||
|
"message": "hola"
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,6 @@ export class LoginComponent implements OnInit {
|
|||||||
masterPassword: string = '';
|
masterPassword: string = '';
|
||||||
|
|
||||||
constructor(private authService: AuthService, private router: Router) {
|
constructor(private authService: AuthService, private router: Router) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -11,6 +11,7 @@ import { AppComponent } from './app.component';
|
|||||||
import { CiphersComponent } from './vault/ciphers.component';
|
import { CiphersComponent } from './vault/ciphers.component';
|
||||||
import { FallbackSrcDirective } from './directives/fallback-src.directive';
|
import { FallbackSrcDirective } from './directives/fallback-src.directive';
|
||||||
import { GroupingsComponent } from './vault/groupings.component';
|
import { GroupingsComponent } from './vault/groupings.component';
|
||||||
|
import { I18nPipe } from './pipes/i18n.pipe';
|
||||||
import { IconComponent } from './vault/icon.component';
|
import { IconComponent } from './vault/icon.component';
|
||||||
import { LoginComponent } from './accounts/login.component';
|
import { LoginComponent } from './accounts/login.component';
|
||||||
import { StopClickDirective } from './directives/stop-click.directive';
|
import { StopClickDirective } from './directives/stop-click.directive';
|
||||||
@ -30,6 +31,7 @@ import { ViewComponent } from './vault/view.component';
|
|||||||
CiphersComponent,
|
CiphersComponent,
|
||||||
FallbackSrcDirective,
|
FallbackSrcDirective,
|
||||||
GroupingsComponent,
|
GroupingsComponent,
|
||||||
|
I18nPipe,
|
||||||
IconComponent,
|
IconComponent,
|
||||||
LoginComponent,
|
LoginComponent,
|
||||||
StopClickDirective,
|
StopClickDirective,
|
||||||
|
18
src/app/pipes/i18n.pipe.ts
Normal file
18
src/app/pipes/i18n.pipe.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {
|
||||||
|
Pipe,
|
||||||
|
PipeTransform,
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { I18nService } from '../../services/i18n.service';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'i18n',
|
||||||
|
})
|
||||||
|
export class I18nPipe implements PipeTransform {
|
||||||
|
constructor(private i18nService: I18nService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
transform(id: string): string {
|
||||||
|
return this.i18nService.t(id);
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,15 @@
|
|||||||
import { webFrame } from 'electron';
|
import { webFrame } from 'electron';
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import {
|
||||||
|
APP_INITIALIZER,
|
||||||
|
NgModule
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
import { DesktopMessagingService } from '../../services/desktopMessaging.service';
|
import { DesktopMessagingService } from '../../services/desktopMessaging.service';
|
||||||
import { DesktopPlatformUtilsService } from '../../services/desktopPlatformUtils.service';
|
import { DesktopPlatformUtilsService } from '../../services/desktopPlatformUtils.service';
|
||||||
import { DesktopStorageService } from '../../services/desktopStorage.service';
|
import { DesktopStorageService } from '../../services/desktopStorage.service';
|
||||||
import { DesktopSecureStorageService } from '../../services/desktopSecureStorage.service';
|
import { DesktopSecureStorageService } from '../../services/desktopSecureStorage.service';
|
||||||
|
import { I18nService } from '../../services/i18n.service';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ApiService,
|
ApiService,
|
||||||
@ -52,6 +56,7 @@ import {
|
|||||||
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('file');
|
webFrame.registerURLSchemeAsPrivileged('file');
|
||||||
|
|
||||||
|
const i18nService = new I18nService(window, './_locales');
|
||||||
const utilsService = new UtilsService();
|
const utilsService = new UtilsService();
|
||||||
const platformUtilsService = new DesktopPlatformUtilsService();
|
const platformUtilsService = new DesktopPlatformUtilsService();
|
||||||
const messagingService = new DesktopMessagingService();
|
const messagingService = new DesktopMessagingService();
|
||||||
@ -69,7 +74,7 @@ const settingsService = new SettingsService(userService, storageService);
|
|||||||
const cipherService = new CipherService(cryptoService, userService, settingsService,
|
const cipherService = new CipherService(cryptoService, userService, settingsService,
|
||||||
apiService, storageService);
|
apiService, storageService);
|
||||||
const folderService = new FolderService(cryptoService, userService,
|
const folderService = new FolderService(cryptoService, userService,
|
||||||
() => 'No Folder', apiService, storageService);
|
() => i18nService.t('noneFolder'), apiService, storageService);
|
||||||
const collectionService = new CollectionService(cryptoService, userService, storageService);
|
const collectionService = new CollectionService(cryptoService, userService, storageService);
|
||||||
const lockService = new LockService(cipherService, folderService, collectionService,
|
const lockService = new LockService(cipherService, folderService, collectionService,
|
||||||
cryptoService, platformUtilsService, storageService,
|
cryptoService, platformUtilsService, storageService,
|
||||||
@ -89,6 +94,10 @@ environmentService.setUrlsFromStorage().then(() => {
|
|||||||
return syncService.fullSync(true);
|
return syncService.fullSync(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function initFactory(i18n: I18nService): Function {
|
||||||
|
return () => i18n.init();
|
||||||
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [],
|
imports: [],
|
||||||
declarations: [],
|
declarations: [],
|
||||||
@ -98,6 +107,13 @@ environmentService.setUrlsFromStorage().then(() => {
|
|||||||
{ provide: FolderServiceAbstraction, useValue: folderService },
|
{ provide: FolderServiceAbstraction, useValue: folderService },
|
||||||
{ provide: CollectionServiceAbstraction, useValue: collectionService },
|
{ provide: CollectionServiceAbstraction, useValue: collectionService },
|
||||||
{ provide: EnvironmentServiceAbstraction, useValue: environmentService },
|
{ provide: EnvironmentServiceAbstraction, useValue: environmentService },
|
||||||
|
{ provide: I18nService, useValue: i18nService },
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: initFactory,
|
||||||
|
deps: [I18nService],
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ServicesModule {
|
export class ServicesModule {
|
||||||
|
@ -9,17 +9,19 @@
|
|||||||
<span class="row-label">Name</span>
|
<span class="row-label">Name</span>
|
||||||
{{cipher.name}}
|
{{cipher.name}}
|
||||||
</div>
|
</div>
|
||||||
<div class="box-content-row">
|
<div *ngIf="cipher.login">
|
||||||
<span class="row-label">URI</span>
|
<div class="box-content-row">
|
||||||
{{cipher.login.uri}}
|
<span class="row-label">URI</span>
|
||||||
</div>
|
{{cipher.login.uri}}
|
||||||
<div class="box-content-row">
|
</div>
|
||||||
<span class="row-label">Username</span>
|
<div class="box-content-row">
|
||||||
{{cipher.login.username}}
|
<span class="row-label">Username</span>
|
||||||
</div>
|
{{cipher.login.username}}
|
||||||
<div class="box-content-row">
|
</div>
|
||||||
<span class="row-label">Password</span>
|
<div class="box-content-row">
|
||||||
{{cipher.login.password}}
|
<span class="row-label">Password</span>
|
||||||
|
{{cipher.login.password}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer">
|
<div class="box-footer">
|
||||||
|
62
src/services/i18n.service.ts
Normal file
62
src/services/i18n.service.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// First locale is the default (English)
|
||||||
|
const SupportedLocales = [
|
||||||
|
'en', 'es',
|
||||||
|
];
|
||||||
|
|
||||||
|
export class I18nService {
|
||||||
|
defaultMessages: any = {};
|
||||||
|
localeMessages: any = {};
|
||||||
|
systemLanguage: string;
|
||||||
|
language: string;
|
||||||
|
inited: boolean;
|
||||||
|
|
||||||
|
constructor(win: Window, private localesDirectory: string) {
|
||||||
|
this.systemLanguage = win.navigator.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(language?: string) {
|
||||||
|
if (this.inited) {
|
||||||
|
throw new Error('i18n already initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inited = true;
|
||||||
|
this.language = language != null ? language : this.systemLanguage;
|
||||||
|
|
||||||
|
if (SupportedLocales.indexOf(this.language) === -1) {
|
||||||
|
this.language = this.language.slice(0, 2);
|
||||||
|
|
||||||
|
if (SupportedLocales.indexOf(this.language) === -1) {
|
||||||
|
this.language = SupportedLocales[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.loadMessages(this.language, this.localeMessages);
|
||||||
|
if (this.language !== SupportedLocales[0]) {
|
||||||
|
await this.loadMessages(SupportedLocales[0], this.defaultMessages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t(id: string): string {
|
||||||
|
return this.translation(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
translation(id: string): string {
|
||||||
|
if (this.localeMessages.hasOwnProperty(id) && this.localeMessages[id]) {
|
||||||
|
return this.localeMessages[id];
|
||||||
|
} else if (this.defaultMessages.hasOwnProperty(id) && this.defaultMessages[id]) {
|
||||||
|
return this.defaultMessages[id];
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadMessages(locale: string, messagesObj: any): Promise<any> {
|
||||||
|
const formattedLocale = locale.replace('-', '_');
|
||||||
|
const file = await fetch(this.localesDirectory + '/' + formattedLocale + '/messages.json');
|
||||||
|
const locales = await file.json();
|
||||||
|
for (const prop in locales) {
|
||||||
|
if (locales.hasOwnProperty(prop)) {
|
||||||
|
messagesObj[prop] = locales[prop].message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,7 @@ const main = {
|
|||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin([
|
||||||
'./src/package.json',
|
'./src/package.json',
|
||||||
{ from: './src/images', to: 'images' },
|
{ from: './src/images', to: 'images' },
|
||||||
|
{ from: './src/_locales', to: '_locales' },
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
externals: [nodeExternals()]
|
externals: [nodeExternals()]
|
||||||
|
Loading…
Reference in New Issue
Block a user