translations

This commit is contained in:
Matt Hill
2026-01-13 15:34:58 -07:00
committed by Aiden McClelland
parent 93fda28393
commit 880aa8040d
20 changed files with 601 additions and 138 deletions

View File

@@ -9,6 +9,7 @@ import { PreloadAllModules, RouterModule } from '@angular/router'
import { WA_LOCATION } from '@ng-web-apis/common'
import initArgon from '@start9labs/argon2'
import {
I18N_PROVIDERS,
provideSetupLogsService,
RELATIVE_URL,
VERSION,
@@ -41,6 +42,7 @@ const version = require('../../../../package.json').version
],
providers: [
NG_EVENT_PLUGINS,
I18N_PROVIDERS,
provideSetupLogsService(ApiService),
tuiButtonOptionsProvider({ size: 'm' }),
{

View File

@@ -6,6 +6,7 @@ import {
ReactiveFormsModule,
Validators,
} from '@angular/forms'
import { i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import {
TuiButton,
@@ -34,7 +35,7 @@ export interface CifsResult {
template: `
<form [formGroup]="form" (ngSubmit)="submit()">
<tui-textfield>
<label tuiLabel>Hostname*</label>
<label tuiLabel>{{ 'Hostname' | i18n }}*</label>
<input
tuiTextfield
formControlName="hostname"
@@ -47,7 +48,7 @@ export interface CifsResult {
/>
<tui-textfield class="input">
<label tuiLabel>Path*</label>
<label tuiLabel>{{ 'Path' | i18n }}*</label>
<input
tuiTextfield
formControlName="path"
@@ -57,7 +58,7 @@ export interface CifsResult {
<tui-error formControlName="path" [error]="[] | tuiFieldError | async" />
<tui-textfield class="input">
<label tuiLabel>Username*</label>
<label tuiLabel>{{ 'Username' | i18n }}*</label>
<input
tuiTextfield
formControlName="username"
@@ -70,7 +71,7 @@ export interface CifsResult {
/>
<tui-textfield class="input">
<label tuiLabel>Password</label>
<label tuiLabel>{{ 'Password' | i18n }}</label>
<input tuiTextfield type="password" formControlName="password" />
<tui-icon tuiPassword />
</tui-textfield>
@@ -83,10 +84,10 @@ export interface CifsResult {
[disabled]="connecting"
(click)="cancel()"
>
Cancel
{{ 'Cancel' | i18n }}
</button>
<button tuiButton [disabled]="form.invalid" [loading]="connecting">
Connect
{{ 'Connect' | i18n }}
</button>
</footer>
</form>
@@ -112,6 +113,7 @@ export interface CifsResult {
TuiError,
TuiFieldErrorPipe,
TuiIcon,
i18nPipe,
],
providers: [
{
@@ -126,6 +128,7 @@ export class CifsComponent {
private readonly dialogs = inject(TuiDialogService)
private readonly api = inject(ApiService)
private readonly context = injectContext<TuiDialogContext<CifsResult>>()
private readonly i18n = inject(i18nPipe)
connecting = false
@@ -181,9 +184,11 @@ export class CifsComponent {
private onFail() {
this.dialogs
.open(
'Unable to connect to network folder. Ensure (1) target computer is connected to LAN, (2) target folder is being shared, and (3) hostname, path, and credentials are accurate.',
this.i18n.transform(
'Unable to connect to network folder. Ensure (1) target computer is connected to LAN, (2) target folder is being shared, and (3) hostname, path, and credentials are accurate.',
),
{
label: 'Connection Failed',
label: this.i18n.transform('Connection Failed'),
size: 's',
},
)

View File

@@ -1,21 +1,22 @@
import { Component, inject } from '@angular/core'
import { i18nPipe } from '@start9labs/shared'
import { TuiButton } from '@taiga-ui/core'
import { TuiDialogContext } from '@taiga-ui/core'
import { injectContext } from '@taiga-ui/polymorpheus'
@Component({
standalone: true,
imports: [TuiButton],
imports: [TuiButton, i18nPipe],
template: `
<p>This drive contains existing StartOS data.</p>
<p>{{ 'This drive contains existing StartOS data.' | i18n }}</p>
<ul>
<li>
<strong class="g-positive">Preserve</strong>
to keep your data.
<strong class="g-positive">{{ 'Preserve' | i18n }}</strong>
{{ 'to keep your data.' | i18n }}
</li>
<li>
<strong class="g-negative">Overwrite</strong>
to discard
<strong class="g-negative">{{ 'Overwrite' | i18n }}</strong>
{{ 'to discard' | i18n }}
</li>
</ul>
<footer>
@@ -24,14 +25,14 @@ import { injectContext } from '@taiga-ui/polymorpheus'
appearance="flat-destructive"
(click)="context.completeWith(false)"
>
Overwrite
{{ 'Overwrite' | i18n }}
</button>
<button
tuiButton
class="preserve-btn"
(click)="context.completeWith(true)"
>
Preserve
{{ 'Preserve' | i18n }}
</button>
</footer>
`,

View File

@@ -1,5 +1,6 @@
import { Component, inject } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { i18nPipe } from '@start9labs/shared'
import { TuiDialogContext, TuiTextfield } from '@taiga-ui/core'
import { TuiDataListWrapper, TuiSelect } from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
@@ -11,11 +12,11 @@ interface Data {
@Component({
standalone: true,
imports: [FormsModule, TuiTextfield, TuiSelect, TuiDataListWrapper],
imports: [FormsModule, TuiTextfield, TuiSelect, TuiDataListWrapper, i18nPipe],
template: `
<p>Multiple backups found. Select which one to restore.</p>
<p>{{ 'Multiple backups found. Select which one to restore.' | i18n }}</p>
<tui-textfield [stringify]="stringify">
<label tuiLabel>Backups</label>
<label tuiLabel>{{ 'Backups' | i18n }}</label>
<input tuiSelect [(ngModel)]="selectedServer" />
<tui-data-list-wrapper
new

View File

@@ -1,5 +1,6 @@
import { Component } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { i18nPipe } from '@start9labs/shared'
import {
TuiButton,
TuiDialogContext,
@@ -11,11 +12,20 @@ import { injectContext } from '@taiga-ui/polymorpheus'
@Component({
standalone: true,
imports: [FormsModule, TuiButton, TuiTextfield, TuiPassword, TuiIcon],
imports: [
FormsModule,
TuiButton,
TuiTextfield,
TuiPassword,
TuiIcon,
i18nPipe,
],
template: `
<p>Enter the password that was used to encrypt this backup.</p>
<p>
{{ 'Enter the password that was used to encrypt this backup.' | i18n }}
</p>
<tui-textfield>
<label tuiLabel>Password</label>
<label tuiLabel>{{ 'Password' | i18n }}</label>
<input
tuiTextfield
type="password"
@@ -26,10 +36,10 @@ import { injectContext } from '@taiga-ui/polymorpheus'
</tui-textfield>
<footer>
<button tuiButton appearance="flat" (click)="context.completeWith(null)">
Cancel
{{ 'Cancel' | i18n }}
</button>
<button tuiButton [disabled]="!password" (click)="unlock()">
Unlock
{{ 'Unlock' | i18n }}
</button>
</footer>
`,

View File

@@ -4,6 +4,7 @@ import { FormsModule } from '@angular/forms'
import {
DiskInfo,
ErrorService,
i18nPipe,
LoadingService,
toGuid,
} from '@start9labs/shared'
@@ -29,27 +30,24 @@ import { ApiService } from '../services/api.service'
import { StateService } from '../services/state.service'
import { PreserveOverwriteDialog } from '../components/preserve-overwrite.dialog'
const OS_DRIVE_TOOLTIP =
'The drive where the StartOS operating system will be installed.'
const DATA_DRIVE_TOOLTIP =
'The drive where your StartOS data (services, settings, etc.) will be stored. This can be the same as the OS drive or a separate drive.'
@Component({
template: `
<section tuiCardLarge="compact">
<header tuiHeader>
<h2 tuiTitle>Select Drives</h2>
<h2 tuiTitle>{{ 'Select Drives' | i18n }}</h2>
</header>
@if (loading) {
<tui-loader />
} @else if (drives.length === 0) {
<p class="no-drives">
No drives found. Please connect a drive and click Refresh.
{{
'No drives found. Please connect a drive and click Refresh.' | i18n
}}
</p>
} @else {
<tui-textfield [stringify]="stringify">
<label tuiLabel>OS Drive</label>
<label tuiLabel>{{ 'OS Drive' | i18n }}</label>
@if (mobile) {
<select
tuiSelect
@@ -71,7 +69,7 @@ const DATA_DRIVE_TOOLTIP =
</tui-textfield>
<tui-textfield [stringify]="stringify">
<label tuiLabel>Data Drive</label>
<label tuiLabel>{{ 'Data Drive' | i18n }}</label>
@if (mobile) {
<select
tuiSelect
@@ -112,7 +110,8 @@ const DATA_DRIVE_TOOLTIP =
<ng-template #driveContent let-drive>
<div class="drive-item">
<span class="drive-name">
{{ drive.vendor || 'Unknown' }} {{ drive.model || 'Drive' }}
{{ drive.vendor || ('Unknown' | i18n) }}
{{ drive.model || ('Drive' | i18n) }}
</span>
<small>
{{ formatCapacity(drive.capacity) }} · {{ drive.logicalname }}
@@ -124,7 +123,7 @@ const DATA_DRIVE_TOOLTIP =
<footer>
@if (drives.length === 0) {
<button tuiButton appearance="secondary" (click)="refresh()">
Refresh
{{ 'Refresh' | i18n }}
</button>
} @else {
<button
@@ -132,7 +131,7 @@ const DATA_DRIVE_TOOLTIP =
[disabled]="!selectedOsDrive || !selectedDataDrive"
(click)="continue()"
>
Continue
{{ 'Continue' | i18n }}
</button>
}
</footer>
@@ -166,6 +165,7 @@ const DATA_DRIVE_TOOLTIP =
TuiTooltip,
TuiHeader,
TuiTitle,
i18nPipe,
],
})
export default class DrivesPage {
@@ -176,11 +176,16 @@ export default class DrivesPage {
private readonly errorService = inject(ErrorService)
private readonly stateService = inject(StateService)
private readonly cdr = inject(ChangeDetectorRef)
private readonly i18n = inject(i18nPipe)
protected readonly mobile = inject(TUI_IS_MOBILE)
readonly osDriveTooltip = OS_DRIVE_TOOLTIP
readonly dataDriveTooltip = DATA_DRIVE_TOOLTIP
readonly osDriveTooltip = this.i18n.transform(
'The drive where the StartOS operating system will be installed.',
)
readonly dataDriveTooltip = this.i18n.transform(
'The drive where your StartOS data (services, settings, etc.) will be stored. This can be the same as the OS drive or a separate drive.',
)
drives: DiskInfo[] = []
loading = true
@@ -189,7 +194,9 @@ export default class DrivesPage {
preserveData: boolean | null = null
readonly stringify = (drive: DiskInfo | null) =>
drive ? `${drive.vendor || 'Unknown'} ${drive.model || 'Drive'}` : ''
drive
? `${drive.vendor || this.i18n.transform('Unknown')} ${drive.model || this.i18n.transform('Drive')}`
: ''
formatCapacity(bytes: number): string {
const gb = bytes / 1e9
@@ -252,7 +259,7 @@ export default class DrivesPage {
this.dialogs
.open<boolean>(new PolymorpheusComponent(PreserveOverwriteDialog), {
label: 'StartOS Data Detected',
label: this.i18n.transform('StartOS Data Detected'),
size: 's',
dismissible: true,
closeable: true,
@@ -277,15 +284,15 @@ export default class DrivesPage {
private showOsDriveWarning() {
this.dialogs
.open<boolean>(TUI_CONFIRM, {
label: 'Warning',
label: this.i18n.transform('Warning'),
size: 's',
data: {
content: `<ul>
<li class="g-negative">Data on the OS drive may be overwritten.</li>
<li class="g-positive">your StartOS data on the data drive will be preserved.</li>
<li class="g-negative">${this.i18n.transform('Data on the OS drive may be overwritten.')}</li>
<li class="g-positive">${this.i18n.transform('your StartOS data on the data drive will be preserved.')}</li>
</ul>`,
yes: 'Continue',
no: 'Cancel',
yes: this.i18n.transform('Continue'),
no: this.i18n.transform('Cancel'),
},
})
.pipe(filter(Boolean))
@@ -296,17 +303,17 @@ export default class DrivesPage {
private showFullWarning(sameDevice: boolean) {
const message = sameDevice
? `<p class="g-negative">Data on this drive will be overwritten.</p>`
: `<p class="g-negative">Data on both drives will be overwritten.</p>`
? `<p class="g-negative">${this.i18n.transform('Data on this drive will be overwritten.')}</p>`
: `<p class="g-negative">${this.i18n.transform('Data on both drives will be overwritten.')}</p>`
this.dialogs
.open<boolean>(TUI_CONFIRM, {
label: 'Warning',
label: this.i18n.transform('Warning'),
size: 's',
data: {
content: message,
yes: 'Continue',
no: 'Cancel',
yes: this.i18n.transform('Continue'),
no: this.i18n.transform('Cancel'),
},
})
.pipe(filter(Boolean))

View File

@@ -1,5 +1,6 @@
import { Component, inject } from '@angular/core'
import { Router } from '@angular/router'
import { i18nPipe } from '@start9labs/shared'
import { TuiAppearance, TuiTitle } from '@taiga-ui/core'
import { TuiAvatar } from '@taiga-ui/kit'
import { TuiCardLarge, TuiCell, TuiHeader } from '@taiga-ui/layout'
@@ -9,31 +10,33 @@ import { StateService } from '../services/state.service'
template: `
<div tuiCardLarge="compact">
<header tuiHeader>
<h2 tuiTitle>Select Setup Flow</h2>
<h2 tuiTitle>{{ 'Select Setup Flow' | i18n }}</h2>
</header>
<button tuiCell="l" (click)="startFresh()">
<tui-avatar appearance="positive" src="@tui.plus" />
<div tuiTitle>
Start Fresh
<div tuiSubtitle>Set up a brand new server</div>
{{ 'Start Fresh' | i18n }}
<div tuiSubtitle>{{ 'Set up a brand new server' | i18n }}</div>
</div>
</button>
<button tuiCell="l" (click)="restore()">
<tui-avatar appearance="warning" src="@tui.archive-restore" />
<div tuiTitle>
Restore from Backup
<div tuiSubtitle>Restore StartOS data from an encrypted backup</div>
{{ 'Restore from Backup' | i18n }}
<div tuiSubtitle>
{{ 'Restore StartOS data from an encrypted backup' | i18n }}
</div>
</div>
</button>
<button tuiCell="l" (click)="transfer()">
<tui-avatar appearance="info" src="@tui.hard-drive-download" />
<div tuiTitle>
Transfer
{{ 'Transfer' | i18n }}
<div tuiSubtitle>
Transfer data from an existing StartOS data drive
{{ 'Transfer data from an existing StartOS data drive' | i18n }}
</div>
</div>
</button>
@@ -46,6 +49,7 @@ import { StateService } from '../services/state.service'
TuiCell,
TuiTitle,
TuiAvatar,
i18nPipe,
],
})
export default class HomePage {

View File

@@ -1,6 +1,7 @@
import { Component, inject } from '@angular/core'
import { Router } from '@angular/router'
import { FormsModule } from '@angular/forms'
import { i18nPipe } from '@start9labs/shared'
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
import { TuiButton, TuiTextfield, TuiTitle } from '@taiga-ui/core'
import { TuiChevron, TuiDataListWrapper, TuiSelect } from '@taiga-ui/kit'
@@ -12,14 +13,14 @@ import { Keyboard, getKeyboardsForLanguage } from '../utils/languages'
template: `
<section tuiCardLarge="compact">
<header tuiHeader>
<h2 tuiTitle>Select Keyboard Layout</h2>
<h2 tuiTitle>{{ 'Select Keyboard Layout' | i18n }}</h2>
</header>
<tui-textfield
tuiChevron
[stringify]="stringify"
[tuiTextfieldCleaner]="false"
>
<label tuiLabel>Keyboard</label>
<label tuiLabel>{{ 'Keyboard' | i18n }}</label>
@if (mobile) {
<select tuiSelect [(ngModel)]="selected" [items]="keyboards"></select>
} @else {
@@ -36,7 +37,7 @@ import { Keyboard, getKeyboardsForLanguage } from '../utils/languages'
<footer>
<button tuiButton [disabled]="!selected" (click)="continue()">
Continue
{{ 'Continue' | i18n }}
</button>
</footer>
</section>
@@ -65,6 +66,7 @@ import { Keyboard, getKeyboardsForLanguage } from '../utils/languages'
TuiDataListWrapper,
TuiHeader,
TuiTitle,
i18nPipe,
],
})
export default class KeyboardPage {

View File

@@ -1,6 +1,7 @@
import { Component, inject } from '@angular/core'
import { Router } from '@angular/router'
import { FormsModule } from '@angular/forms'
import { i18nPipe, i18nService } from '@start9labs/shared'
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
import { TuiButton, TuiTextfield, TuiTitle } from '@taiga-ui/core'
import { TuiChevron, TuiDataListWrapper, TuiSelect } from '@taiga-ui/kit'
@@ -20,22 +21,30 @@ import {
<h2 tuiTitle>
<span class="inline-title">
<img src="assets/img/icon.png" alt="Start9" />
Welcome to StartOS
{{ 'Welcome to' | i18n }} StartOS
</span>
<span tuiSubtitle>Select your language</span>
<span tuiSubtitle>{{ 'Select your language' | i18n }}</span>
</h2>
</header>
<tui-textfield
tuiChevron
[stringify]="stringify"
[tuiTextfieldCleaner]="false"
>
<label tuiLabel>Language</label>
<label tuiLabel>{{ 'Language' | i18n }}</label>
@if (mobile) {
<select tuiSelect [(ngModel)]="selected" [items]="languages"></select>
<select
tuiSelect
[(ngModel)]="selected"
[items]="languages"
(ngModelChange)="onLanguageChange($event)"
></select>
} @else {
<input tuiSelect [(ngModel)]="selected" />
<input
tuiSelect
[(ngModel)]="selected"
(ngModelChange)="onLanguageChange($event)"
/>
}
@if (!mobile) {
<tui-data-list-wrapper
@@ -48,17 +57,16 @@ import {
</tui-textfield>
<ng-template #itemContent let-item>
@let lang = asLanguage(item);
<div class="language-item">
<span>{{ item.nativeName }}</span>
@if (item.name !== item.nativeName) {
<small>{{ item.name }}</small>
}
<span>{{ lang.nativeName }}</span>
<small>{{ lang.tuiName | i18n }}</small>
</div>
</ng-template>
<footer>
<button tuiButton [disabled]="!selected" (click)="continue()">
Continue
{{ 'Continue' | i18n }}
</button>
</footer>
</section>
@@ -90,29 +98,43 @@ import {
TuiDataListWrapper,
TuiHeader,
TuiTitle,
i18nPipe,
],
})
export default class LanguagePage {
private readonly router = inject(Router)
private readonly stateService = inject(StateService)
private readonly i18nService = inject(i18nService)
protected readonly mobile = inject(TUI_IS_MOBILE)
readonly languages = LANGUAGES
selected =
LANGUAGES.find(l => l.code === this.stateService.language) || LANGUAGES[0]
readonly stringify = (lang: Language) => lang.nativeName
readonly asLanguage = (item: unknown): Language => item as Language
constructor() {
if (this.selected) {
this.i18nService.setLanguage(this.selected.tuiName)
}
}
onLanguageChange(language: Language) {
if (language) {
this.i18nService.setLanguage(language.tuiName)
}
}
async continue() {
if (this.selected) {
this.stateService.language = this.selected.code
if (this.stateService.kiosk) {
// Check if we need keyboard selection
if (needsKeyboardSelection(this.selected.code)) {
await this.router.navigate(['/keyboard'])
} else {
// Auto-select the only keyboard option
this.stateService.keyboard = getDefaultKeyboard(
this.selected.code,
).code

View File

@@ -10,7 +10,7 @@ import {
DialogService,
formatProgress,
getErrorMessage,
i18nKey,
i18nPipe,
InitializingComponent,
LoadingService,
} from '@start9labs/shared'
@@ -33,9 +33,11 @@ import { StateService } from '../services/state.service'
template: `
@if (error(); as err) {
<section>
<h1>Error initializing server</h1>
<h1>{{ 'Error initializing server' | i18n }}</h1>
<p>{{ err }}</p>
<button tuiButton (click)="restart()">Restart server</button>
<button tuiButton (click)="restart()">
{{ 'Restart server' | i18n }}
</button>
</section>
} @else {
<app-initializing [initialSetup]="true" [progress]="progress()" />
@@ -57,7 +59,7 @@ import { StateService } from '../services/state.service'
--tui-background-neutral-1: rgba(0, 0, 0, 0.1);
}
`,
imports: [InitializingComponent, TuiButton],
imports: [InitializingComponent, TuiButton, i18nPipe],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class LoadingPage {
@@ -65,6 +67,7 @@ export default class LoadingPage {
private readonly loader = inject(LoadingService)
private readonly dialog = inject(DialogService)
private readonly router = inject(Router)
private readonly i18n = inject(i18nPipe)
readonly type = inject(StateService).setupType
readonly progress = toSignal(
@@ -117,7 +120,7 @@ export default class LoadingPage {
try {
await this.api.restart()
this.dialog
.openAlert('Wait 1-2 minutes and refresh the page' as i18nKey, {
.openAlert('Wait 1-2 minutes and refresh the page', {
label: 'Server is restarting',
})
.subscribe()

View File

@@ -8,7 +8,7 @@ import {
ReactiveFormsModule,
Validators,
} from '@angular/forms'
import { ErrorService, i18nKey, LoadingService } from '@start9labs/shared'
import { ErrorService, i18nPipe, LoadingService } from '@start9labs/shared'
import { TuiAutoFocus, TuiMapperPipe, TuiValidator } from '@taiga-ui/cdk'
import {
TuiButton,
@@ -31,13 +31,15 @@ import { StateService } from '../services/state.service'
<header tuiHeader>
<h2 tuiTitle>
{{
isRequired ? 'Set Master Password' : 'Set New Password (Optional)'
isRequired
? ('Set Master Password' | i18n)
: ('Set New Password (Optional)' | i18n)
}}
<span tuiSubtitle>
{{
isRequired
? 'Make it good. Write it down.'
: 'Skip to keep your existing password.'
? ('Make it good. Write it down.' | i18n)
: ('Skip to keep your existing password.' | i18n)
}}
</span>
</h2>
@@ -46,7 +48,9 @@ import { StateService } from '../services/state.service'
<form [formGroup]="form" (ngSubmit)="submit()">
<tui-textfield>
<label tuiLabel>
{{ isRequired ? 'Enter Password' : 'New Password' }}
{{
isRequired ? ('Enter Password' | i18n) : ('New Password' | i18n)
}}
</label>
<input
tuiTextfield
@@ -63,7 +67,7 @@ import { StateService } from '../services/state.service'
/>
<tui-textfield [style.margin-top.rem]="1">
<label tuiLabel>Confirm Password</label>
<label tuiLabel>{{ 'Confirm Password' | i18n }}</label>
<input
tuiTextfield
type="password"
@@ -88,7 +92,7 @@ import { StateService } from '../services/state.service'
: form.controls.password.value && form.invalid
"
>
Finish
{{ 'Finish' | i18n }}
</button>
@if (!isRequired) {
<button
@@ -97,7 +101,7 @@ import { StateService } from '../services/state.service'
type="button"
(click)="skip()"
>
Skip
{{ 'Skip' | i18n }}
</button>
}
</footer>
@@ -127,6 +131,7 @@ import { StateService } from '../services/state.service'
TuiMapperPipe,
TuiHeader,
TuiTitle,
i18nPipe,
],
providers: [
tuiValidationErrorsProvider({
@@ -142,6 +147,7 @@ export default class PasswordPage {
private readonly loader = inject(LoadingService)
private readonly errorService = inject(ErrorService)
private readonly stateService = inject(StateService)
private readonly i18n = inject(i18nPipe)
// Password is required only for fresh install
readonly isRequired = this.stateService.setupType === 'fresh'
@@ -156,7 +162,9 @@ export default class PasswordPage {
})
readonly validator = (value: string) => (control: AbstractControl) =>
value === control.value ? null : { match: 'Passwords do not match' }
value === control.value
? null
: { match: this.i18n.transform('Passwords do not match') }
async skip() {
// Skip means no new password - pass null
@@ -168,7 +176,7 @@ export default class PasswordPage {
}
private async executeSetup(password: string | null) {
const loader = this.loader.open('Starting setup...' as i18nKey).subscribe()
const loader = this.loader.open('Starting setup').subscribe()
try {
if (this.stateService.setupType === 'attach') {

View File

@@ -1,6 +1,6 @@
import { Component, inject } from '@angular/core'
import { Router } from '@angular/router'
import { ErrorService } from '@start9labs/shared'
import { ErrorService, i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import {
TuiButton,
@@ -26,12 +26,12 @@ import { UnlockPasswordDialog } from '../components/unlock-password.dialog'
<section tuiCardLarge="compact">
<header tuiHeader>
<h2 tuiTitle>
Select Backup
{{ 'Select Backup' | i18n }}
<span tuiSubtitle>
Select the StartOS backup you want to restore
{{ 'Select the StartOS backup you want to restore' | i18n }}
<a class="refresh" (click)="refresh()">
<tui-icon icon="@tui.rotate-cw" />
Refresh
{{ 'Refresh' | i18n }}
</a>
</span>
</h2>
@@ -48,7 +48,7 @@ import { UnlockPasswordDialog } from '../components/unlock-password.dialog'
[(tuiDropdownOpen)]="open"
style="width: 100%"
>
Select Backup
{{ 'Select Backup' | i18n }}
</button>
<ng-template #dropdown>
@@ -56,10 +56,10 @@ import { UnlockPasswordDialog } from '../components/unlock-password.dialog'
<tui-opt-group>
<button tuiOption new (click)="openCifs()">
<tui-icon icon="@tui.folder-plus" />
Open Network Backup
{{ 'Open Network Backup' | i18n }}
</button>
</tui-opt-group>
<tui-opt-group label="Physical Backups">
<tui-opt-group [label]="'Physical Backups' | i18n">
@for (server of physicalServers; track server.id) {
<button tuiOption new (click)="selectPhysicalBackup(server)">
<div class="server-item">
@@ -71,7 +71,7 @@ import { UnlockPasswordDialog } from '../components/unlock-password.dialog'
</div>
</button>
} @empty {
<div class="no-items">No physical backups</div>
<div class="no-items">{{ 'No physical backups' | i18n }}</div>
}
</tui-opt-group>
</tui-data-list>
@@ -117,6 +117,7 @@ import { UnlockPasswordDialog } from '../components/unlock-password.dialog'
TuiOptGroup,
TuiTitle,
TuiHeader,
i18nPipe,
],
})
export default class RestorePage {
@@ -125,6 +126,7 @@ export default class RestorePage {
private readonly dialogs = inject(TuiDialogService)
private readonly errorService = inject(ErrorService)
private readonly stateService = inject(StateService)
private readonly i18n = inject(i18nPipe)
loading = true
open = false
@@ -143,7 +145,7 @@ export default class RestorePage {
this.open = false
this.dialogs
.open<CifsResult>(CIFS, {
label: 'Connect Network Folder',
label: this.i18n.transform('Connect Network Folder'),
size: 's',
})
.subscribe(result => {
@@ -178,7 +180,7 @@ export default class RestorePage {
) {
this.dialogs
.open<StartOSDiskInfoWithId | null>(SELECT_NETWORK_BACKUP, {
label: 'Select Network Backup',
label: this.i18n.transform('Select Network Backup'),
size: 's',
data: { servers },
})
@@ -195,7 +197,7 @@ export default class RestorePage {
) {
this.dialogs
.open<string | null>(new PolymorpheusComponent(UnlockPasswordDialog), {
label: 'Unlock Backup',
label: this.i18n.transform('Unlock Backup'),
size: 's',
})
.subscribe(password => {

View File

@@ -6,7 +6,7 @@ import {
ViewChild,
DOCUMENT,
} from '@angular/core'
import { DownloadHTMLService, ErrorService } from '@start9labs/shared'
import { DownloadHTMLService, ErrorService, i18nPipe } from '@start9labs/shared'
import { TuiIcon, TuiLoader, TuiTitle } from '@taiga-ui/core'
import { TuiAvatar } from '@taiga-ui/kit'
import { TuiCardLarge, TuiCell, TuiHeader } from '@taiga-ui/layout'
@@ -24,16 +24,17 @@ import { SetupCompleteRes } from '../types'
<h2 tuiTitle>
<span class="inline-title">
<tui-icon icon="@tui.circle-check-big" class="g-positive" />
Setup Complete!
{{ 'Setup Complete!' | i18n }}
</span>
@if (!stateService.kiosk) {
<span tuiSubtitle>
{{
stateService.setupType === 'restore'
? 'You can unplug your backup drive'
? ('You can unplug your backup drive' | i18n)
: stateService.setupType === 'transfer'
? 'You can unplug your transfer drive'
: 'http://start.local was for setup only. It will no longer work.'
? ('You can unplug your transfer drive' | i18n)
: ('http://start.local was for setup only. It will no longer work.'
| i18n)
}}
</span>
}
@@ -48,9 +49,12 @@ import { SetupCompleteRes } from '../types'
<button tuiCell="l" [disabled]="downloaded" (click)="download()">
<tui-avatar appearance="secondary" src="@tui.download" />
<div tuiTitle>
Download Address Info
{{ 'Download Address Info' | i18n }}
<div tuiSubtitle>
Contains your server's permanent local address and Root CA
{{
"Contains your server's permanent local address and Root CA"
| i18n
}}
</div>
</div>
@if (downloaded) {
@@ -69,9 +73,11 @@ import { SetupCompleteRes } from '../types'
>
<tui-avatar appearance="secondary" src="@tui.usb" />
<div tuiTitle>
Remove USB Media
{{ 'Remove USB Media' | i18n }}
<div tuiSubtitle>
Remove the USB installation media from your server
{{
'Remove the USB installation media from your server' | i18n
}}
</div>
</div>
@if (usbRemoved) {
@@ -88,14 +94,14 @@ import { SetupCompleteRes } from '../types'
>
<tui-avatar appearance="secondary" src="@tui.rotate-cw" />
<div tuiTitle>
Restart Server
{{ 'Restart Server' | i18n }}
<div tuiSubtitle>
@if (rebooting) {
Waiting for server to come back online...
{{ 'Waiting for server to come back online' | i18n }}
} @else if (rebooted) {
Server is back online
{{ 'Server is back online' | i18n }}
} @else {
Restart your server to complete setup
{{ 'Restart your server to complete setup' | i18n }}
}
</div>
</div>
@@ -117,7 +123,7 @@ import { SetupCompleteRes } from '../types'
>
<tui-avatar appearance="secondary" src="@tui.external-link" />
<div tuiTitle>
Open Local Address
{{ 'Open Local Address' | i18n }}
<div tuiSubtitle>{{ lanAddress }}</div>
</div>
</button>
@@ -135,8 +141,10 @@ import { SetupCompleteRes } from '../types'
>
<tui-avatar appearance="secondary" src="@tui.log-in" />
<div tuiTitle>
Continue to Login
<div tuiSubtitle>Proceed to the StartOS login screen</div>
{{ 'Continue to Login' | i18n }}
<div tuiSubtitle>
{{ 'Proceed to the StartOS login screen' | i18n }}
</div>
</div>
</button>
}
@@ -165,6 +173,7 @@ import { SetupCompleteRes } from '../types'
DocumentationComponent,
TuiHeader,
TuiTitle,
i18nPipe,
],
})
export default class SuccessPage implements AfterViewInit {
@@ -175,6 +184,7 @@ export default class SuccessPage implements AfterViewInit {
private readonly errorService = inject(ErrorService)
private readonly api = inject(ApiService)
private readonly downloadHtml = inject(DownloadHTMLService)
private readonly i18n = inject(i18nPipe)
readonly stateService = inject(StateService)
@@ -270,7 +280,9 @@ export default class SuccessPage implements AfterViewInit {
}
throw new Error(
'Server did not come back online. Please check your server and try accessing it manually.',
this.i18n.transform(
'Server did not come back online. Please check your server and try accessing it manually.',
),
)
}
}

View File

@@ -1,6 +1,6 @@
import { Component, inject } from '@angular/core'
import { Router } from '@angular/router'
import { DiskInfo, ErrorService, toGuid } from '@start9labs/shared'
import { DiskInfo, ErrorService, i18nPipe, toGuid } from '@start9labs/shared'
import {
TuiButton,
TuiDataList,
@@ -22,12 +22,14 @@ import { StateService } from '../services/state.service'
<section tuiCardLarge="compact">
<header tuiHeader>
<h2 tuiTitle>
Transfer Data
{{ 'Transfer Data' | i18n }}
<span tuiSubtitle>
Select the drive containing your existing StartOS data
{{
'Select the drive containing your existing StartOS data' | i18n
}}
<a class="refresh" (click)="refresh()">
<tui-icon icon="@tui.rotate-cw" />
Refresh
{{ 'Refresh' | i18n }}
</a>
</span>
</h2>
@@ -44,7 +46,7 @@ import { StateService } from '../services/state.service'
[(tuiDropdownOpen)]="open"
style="width: 100%"
>
Select Drive
{{ 'Select Drive' | i18n }}
</button>
<ng-template #dropdown>
@@ -57,7 +59,9 @@ import { StateService } from '../services/state.service'
</div>
</button>
} @empty {
<div class="no-items">No StartOS data drives found</div>
<div class="no-items">
{{ 'No StartOS data drives found' | i18n }}
</div>
}
</tui-data-list>
</ng-template>
@@ -101,6 +105,7 @@ import { StateService } from '../services/state.service'
TuiLoader,
TuiTitle,
TuiHeader,
i18nPipe,
],
})
export default class TransferPage {
@@ -109,6 +114,7 @@ export default class TransferPage {
private readonly dialogs = inject(TuiDialogService)
private readonly errorService = inject(ErrorService)
private readonly stateService = inject(StateService)
private readonly i18n = inject(i18nPipe)
loading = true
open = false
@@ -127,14 +133,14 @@ export default class TransferPage {
this.open = false
const WARNING_OPTIONS: Partial<TuiDialogOptions<TuiConfirmData>> = {
label: 'Warning',
label: this.i18n.transform('Warning'),
size: 's',
data: {
content: `After transferring data from this drive, <strong>do not</strong>
attempt to boot into it again as a Start9 Server. This may result in
services malfunctioning, data corruption, or loss of funds.`,
yes: 'Continue',
no: 'Cancel',
content: this.i18n.transform(
'After transferring data from this drive, do not attempt to boot into it again as a Start9 Server. This may result in services malfunctioning, data corruption, or loss of funds.',
),
yes: this.i18n.transform('Continue'),
no: this.i18n.transform('Cancel'),
},
}

View File

@@ -1,20 +1,22 @@
export interface Language {
code: string
name: string
nativeName: string
}
import { i18nKey } from '@start9labs/shared'
export interface Keyboard {
code: string
name: string
}
export interface Language {
code: string
tuiName: i18nKey
nativeName: string
}
export const LANGUAGES: Language[] = [
{ code: 'en', name: 'English', nativeName: 'English' },
{ code: 'es', name: 'Spanish', nativeName: 'Español' },
{ code: 'de', name: 'German', nativeName: 'Deutsch' },
{ code: 'fr', name: 'French', nativeName: 'Français' },
{ code: 'pl', name: 'Polish', nativeName: 'Polski' },
{ code: 'en', tuiName: 'english', nativeName: 'English' },
{ code: 'es', tuiName: 'spanish', nativeName: 'Español' },
{ code: 'de', tuiName: 'german', nativeName: 'Deutsch' },
{ code: 'fr', tuiName: 'french', nativeName: 'Français' },
{ code: 'pl', tuiName: 'polish', nativeName: 'Polski' },
]
export const KEYBOARDS_BY_LANGUAGE: Record<string, Keyboard[]> = {

View File

@@ -597,5 +597,80 @@ export default {
627: 'UI öffnen',
628: 'In Zwischenablage kopiert',
629: 'StartOS wird installiert',
630: 'Wähle deine Sprache',
631: 'Tastaturlayout auswählen',
632: 'Tastatur',
633: 'Einrichtungsablauf auswählen',
634: 'Neu beginnen',
635: 'Einen brandneuen Server einrichten',
636: 'Aus Backup wiederherstellen',
637: 'StartOS-Daten aus einem verschlüsselten Backup wiederherstellen',
638: 'Daten von einem bestehenden StartOS-Datenträger übertragen',
639: 'Laufwerke auswählen',
640: 'Keine Laufwerke gefunden. Bitte schließen Sie ein Laufwerk an und klicken Sie auf Aktualisieren.',
641: 'OS-Laufwerk',
642: 'Datenlaufwerk',
643: 'StartOS-Daten erkannt',
644: 'Daten auf dem OS-Laufwerk könnten überschrieben werden.',
645: 'Ihre StartOS-Daten auf dem Datenlaufwerk bleiben erhalten.',
646: 'Daten auf diesem Laufwerk werden überschrieben.',
647: 'Daten auf beiden Laufwerken werden überschrieben.',
648: 'Backup auswählen',
649: 'Wählen Sie das StartOS-Backup aus, das Sie wiederherstellen möchten',
650: 'Netzwerk-Backup öffnen',
651: 'Physische Backups',
652: 'Keine physischen Backups',
653: 'Netzwerkordner verbinden',
654: 'Netzwerk-Backup auswählen',
655: 'Backup entsperren',
656: 'Daten übertragen',
657: 'Wählen Sie das Laufwerk mit Ihren bestehenden StartOS-Daten aus',
658: 'Laufwerk auswählen',
659: 'Keine StartOS-Datenlaufwerke gefunden',
660: 'Master-Passwort festlegen',
661: 'Neues Passwort festlegen (optional)',
662: 'Machen Sie es gut. Schreiben Sie es auf.',
663: 'Überspringen, um Ihr bestehendes Passwort beizubehalten.',
664: 'Passwort eingeben',
665: 'Passwort bestätigen',
666: 'Fertigstellen',
667: 'Einrichtung wird gestartet',
670: 'Warten Sie 12 Minuten und aktualisieren Sie die Seite',
672: 'Einrichtung abgeschlossen!',
673: 'Sie können Ihr Backup-Laufwerk entfernen',
674: 'Sie können Ihr Übertragungs-Laufwerk entfernen',
675: 'http://start.local war nur für die Einrichtung gedacht. Es funktioniert nicht mehr.',
676: 'Adressinformationen herunterladen',
677: 'Enthält die permanente lokale Adresse Ihres Servers und die Root-CA',
678: 'USB-Medium entfernen',
679: 'Entfernen Sie das USB-Installationsmedium aus Ihrem Server',
680: 'Server neu starten',
681: 'Warten, bis der Server wieder online ist',
682: 'Server ist wieder online',
683: 'Starten Sie Ihren Server neu, um die Einrichtung abzuschließen',
684: 'Lokale Adresse öffnen',
685: 'Weiter zur Anmeldung',
686: 'Zur StartOS-Anmeldeseite wechseln',
687: 'Der Server ist nicht wieder online gegangen. Bitte überprüfen Sie Ihren Server und versuchen Sie, manuell darauf zuzugreifen.',
691: 'Dieses Feld ist erforderlich',
692: 'Verbindung fehlgeschlagen',
693: 'Verbindung zum Netzwerkordner nicht möglich. Stellen Sie sicher, dass (1) der Zielcomputer mit dem LAN verbunden ist, (2) der Zielordner freigegeben ist und (3) Hostname, Pfad und Anmeldedaten korrekt sind.',
694: 'Dieses Laufwerk enthält bestehende StartOS-Daten.',
695: 'um Ihre Daten zu behalten.',
696: 'um zu verwerfen',
697: 'Geben Sie das Passwort ein, das zum Verschlüsseln dieses Backups verwendet wurde.',
698: 'Mehrere Backups gefunden. Wählen Sie aus, welches wiederhergestellt werden soll.',
699: 'Backups',
700: 'Das Laufwerk, auf dem das StartOS-Betriebssystem installiert wird.',
701: 'Das Laufwerk, auf dem Ihre StartOS-Daten (Dienste, Einstellungen usw.) gespeichert werden. Dies kann dasselbe wie das OS-Laufwerk oder ein separates Laufwerk sein.',
702: 'Versuchen Sie nach der Datenübertragung von diesem Laufwerk nicht, erneut als Start9-Server davon zu booten. Dies kann zu Fehlfunktionen von Diensten, Datenbeschädigung oder Geldverlust führen.',
703: 'Muss mindestens 12 Zeichen lang sein',
704: 'Darf höchstens 64 Zeichen lang sein',
705: 'Passwörter stimmen nicht überein',
706: 'Beibehalten',
707: 'Überschreiben',
708: 'Entsperren',
709: 'Laufwerk',
710: 'Übertragen',
711: 'Die Liste ist leer',
} satisfies i18n

View File

@@ -595,6 +595,82 @@ export const ENGLISH = {
'Upload': 626, // as in, upload a file
'Open UI': 627, // as in, upload a file
'Copied to clipboard': 628,
// Setup wizard keys
'Installing StartOS': 629,
'Select your language': 630,
'Select Keyboard Layout': 631,
'Keyboard': 632,
'Select Setup Flow': 633,
'Start Fresh': 634,
'Set up a brand new server': 635,
'Restore from Backup': 636,
'Restore StartOS data from an encrypted backup': 637,
'Transfer data from an existing StartOS data drive': 638,
'Select Drives': 639, // as in storage devices
'No drives found. Please connect a drive and click Refresh.': 640,
'OS Drive': 641,
'Data Drive': 642,
'StartOS Data Detected': 643,
'Data on the OS drive may be overwritten.': 644,
'your StartOS data on the data drive will be preserved.': 645,
'Data on this drive will be overwritten.': 646,
'Data on both drives will be overwritten.': 647,
'Select Backup': 648,
'Select the StartOS backup you want to restore': 649,
'Open Network Backup': 650, // as in, a backup stored on a networked device
'Physical Backups': 651, // as in, a backup stored on a physical drive
'No physical backups': 652,
'Connect Network Folder': 653,
'Select Network Backup': 654,
'Unlock Backup': 655,
'Transfer Data': 656,
'Select the drive containing your existing StartOS data': 657,
'Select Drive': 658,
'No StartOS data drives found': 659,
'Set Master Password': 660,
'Set New Password (Optional)': 661,
'Make it good. Write it down.': 662,
'Skip to keep your existing password.': 663,
'Enter Password': 664,
'Confirm Password': 665,
'Finish': 666,
'Starting setup': 667,
'Wait 1-2 minutes and refresh the page': 670,
'Setup Complete!': 672,
'You can unplug your backup drive': 673,
'You can unplug your transfer drive': 674,
'http://start.local was for setup only. It will no longer work.': 675,
'Download Address Info': 676,
"Contains your server's permanent local address and Root CA": 677,
'Remove USB Media': 678,
'Remove the USB installation media from your server': 679,
'Restart Server': 680,
'Waiting for server to come back online': 681,
'Server is back online': 682,
'Restart your server to complete setup': 683,
'Open Local Address': 684,
'Continue to Login': 685,
'Proceed to the StartOS login screen': 686,
'Server did not come back online. Please check your server and try accessing it manually.': 687,
'This field is required': 691,
'Connection Failed': 692,
'Unable to connect to network folder. Ensure (1) target computer is connected to LAN, (2) target folder is being shared, and (3) hostname, path, and credentials are accurate.': 693,
'This drive contains existing StartOS data.': 694,
'to keep your data.': 695,
'to discard': 696,
'Enter the password that was used to encrypt this backup.': 697,
'Multiple backups found. Select which one to restore.': 698,
'Backups': 699,
'The drive where the StartOS operating system will be installed.': 700,
'The drive where your StartOS data (services, settings, etc.) will be stored. This can be the same as the OS drive or a separate drive.': 701,
'After transferring data from this drive, do not attempt to boot into it again as a Start9 Server. This may result in services malfunctioning, data corruption, or loss of funds.': 702,
'Must be 12 characters or greater': 703,
'Must be 64 character or less': 704,
'Passwords do not match': 705,
'Preserve': 706,
'Overwrite': 707,
'Unlock': 708,
'Drive': 709, // as in, a storage device
'Transfer': 710, // the verb
'The list is empty': 711,
} as const

View File

@@ -597,5 +597,80 @@ export default {
627: 'Abrir UI',
628: 'Copiado al portapapeles',
629: 'Instalando StartOS',
630: 'Selecciona tu idioma',
631: 'Seleccionar distribución del teclado',
632: 'Teclado',
633: 'Seleccionar flujo de configuración',
634: 'Empezar desde cero',
635: 'Configurar un servidor completamente nuevo',
636: 'Restaurar desde copia de seguridad',
637: 'Restaurar datos de StartOS desde una copia de seguridad cifrada',
638: 'Transferir datos desde una unidad de datos StartOS existente',
639: 'Seleccionar unidades',
640: 'No se encontraron unidades. Conecte una unidad y haga clic en Actualizar.',
641: 'Unidad del sistema operativo',
642: 'Unidad de datos',
643: 'Datos de StartOS detectados',
644: 'Los datos de la unidad del sistema operativo pueden sobrescribirse.',
645: 'Sus datos de StartOS en la unidad de datos se conservarán.',
646: 'Los datos de esta unidad se sobrescribirán.',
647: 'Los datos de ambas unidades se sobrescribirán.',
648: 'Seleccionar copia de seguridad',
649: 'Seleccione la copia de seguridad de StartOS que desea restaurar',
650: 'Abrir copia de seguridad de red',
651: 'Copias de seguridad físicas',
652: 'No hay copias de seguridad físicas',
653: 'Conectar carpeta de red',
654: 'Seleccionar copia de seguridad de red',
655: 'Desbloquear copia de seguridad',
656: 'Transferir datos',
657: 'Seleccione la unidad que contiene sus datos StartOS existentes',
658: 'Seleccionar unidad',
659: 'No se encontraron unidades de datos StartOS',
660: 'Establecer contraseña maestra',
661: 'Establecer nueva contraseña (opcional)',
662: 'Que sea buena. Escríbala.',
663: 'Omitir para mantener su contraseña existente.',
664: 'Introducir contraseña',
665: 'Confirmar contraseña',
666: 'Finalizar',
667: 'Iniciando configuración',
670: 'Espere 12 minutos y actualice la página',
672: '¡Configuración completa!',
673: 'Puede desconectar su unidad de copia de seguridad',
674: 'Puede desconectar su unidad de transferencia',
675: 'http://start.local era solo para la configuración. Ya no funcionará.',
676: 'Descargar información de direcciones',
677: 'Contiene la dirección local permanente de su servidor y la CA raíz',
678: 'Retirar medio USB',
679: 'Retire el medio de instalación USB de su servidor',
680: 'Reiniciar servidor',
681: 'Esperando a que el servidor vuelva a estar en línea',
682: 'El servidor ha vuelto a estar en línea',
683: 'Reinicie su servidor para completar la configuración',
684: 'Abrir dirección local',
685: 'Continuar al inicio de sesión',
686: 'Ir a la pantalla de inicio de sesión de StartOS',
687: 'El servidor no volvió a estar en línea. Verifique su servidor e intente acceder manualmente.',
691: 'Este campo es obligatorio',
692: 'Conexión fallida',
693: 'No se pudo conectar a la carpeta de red. Asegúrese de que (1) el equipo de destino esté conectado a la LAN, (2) la carpeta de destino esté compartida y (3) el nombre de host, la ruta y las credenciales sean correctos.',
694: 'Esta unidad contiene datos existentes de StartOS.',
695: 'para conservar sus datos.',
696: 'para descartar',
697: 'Introduzca la contraseña que se utilizó para cifrar esta copia de seguridad.',
698: 'Se encontraron varias copias de seguridad. Seleccione cuál restaurar.',
699: 'Copias de seguridad',
700: 'La unidad donde se instalará el sistema operativo StartOS.',
701: 'La unidad donde se almacenarán sus datos de StartOS (servicios, ajustes, etc.). Puede ser la misma que la unidad del sistema operativo o una unidad separada.',
702: 'Después de transferir datos desde esta unidad, no intente arrancar desde ella nuevamente como un servidor Start9. Esto puede provocar fallos en los servicios, corrupción de datos o pérdida de fondos.',
703: 'Debe tener 12 caracteres o más',
704: 'Debe tener 64 caracteres o menos',
705: 'Las contraseñas no coinciden',
706: 'Conservar',
707: 'Sobrescribir',
708: 'Desbloquear',
709: 'Unidad',
710: 'Transferir',
711: 'La lista está vacía',
} satisfies i18n

View File

@@ -597,5 +597,80 @@ export default {
627: 'Ouvrir UI',
628: 'Copié dans le presse-papiers',
629: 'Installation de StartOS',
630: 'Sélectionnez votre langue',
631: 'Sélectionner la disposition du clavier',
632: 'Clavier',
633: 'Sélectionner le mode de configuration',
634: 'Démarrer à neuf',
635: 'Configurer un tout nouveau serveur',
636: 'Restaurer à partir dune sauvegarde',
637: 'Restaurer les données StartOS à partir dune sauvegarde chiffrée',
638: 'Transférer les données depuis un disque de données StartOS existant',
639: 'Sélectionner les disques',
640: 'Aucun disque trouvé. Veuillez connecter un disque et cliquer sur Actualiser.',
641: 'Disque du système',
642: 'Disque de données',
643: 'Données StartOS détectées',
644: 'Les données du disque système peuvent être écrasées.',
645: 'Vos données StartOS sur le disque de données seront conservées.',
646: 'Les données de ce disque seront écrasées.',
647: 'Les données des deux disques seront écrasées.',
648: 'Sélectionner une sauvegarde',
649: 'Sélectionnez la sauvegarde StartOS que vous souhaitez restaurer',
650: 'Ouvrir une sauvegarde réseau',
651: 'Sauvegardes physiques',
652: 'Aucune sauvegarde physique',
653: 'Connecter un dossier réseau',
654: 'Sélectionner une sauvegarde réseau',
655: 'Déverrouiller la sauvegarde',
656: 'Transférer les données',
657: 'Sélectionnez le disque contenant vos données StartOS existantes',
658: 'Sélectionner le disque',
659: 'Aucun disque de données StartOS trouvé',
660: 'Définir le mot de passe maître',
661: 'Définir un nouveau mot de passe (facultatif)',
662: 'Choisissez-le bien. Notez-le.',
663: 'Ignorer pour conserver votre mot de passe existant.',
664: 'Saisir le mot de passe',
665: 'Confirmer le mot de passe',
666: 'Terminer',
667: 'Démarrage de la configuration',
670: 'Attendez 1 à 2 minutes puis actualisez la page',
672: 'Configuration terminée !',
673: 'Vous pouvez débrancher votre disque de sauvegarde',
674: 'Vous pouvez débrancher votre disque de transfert',
675: 'http://start.local était réservé à la configuration. Il ne fonctionnera plus.',
676: 'Télécharger les informations dadresse',
677: 'Contient ladresse locale permanente de votre serveur et la CA racine',
678: 'Retirer le support USB',
679: 'Retirez le support dinstallation USB de votre serveur',
680: 'Redémarrer le serveur',
681: 'En attente du retour en ligne du serveur',
682: 'Le serveur est de nouveau en ligne',
683: 'Redémarrez votre serveur pour terminer la configuration',
684: 'Ouvrir ladresse locale',
685: 'Continuer vers la connexion',
686: 'Accéder à lécran de connexion StartOS',
687: 'Le serveur nest pas revenu en ligne. Veuillez vérifier votre serveur et essayer dy accéder manuellement.',
691: 'Ce champ est requis',
692: 'Échec de la connexion',
693: 'Impossible de se connecter au dossier réseau. Assurez-vous que (1) lordinateur cible est connecté au LAN, (2) le dossier cible est partagé et (3) le nom dhôte, le chemin et les identifiants sont corrects.',
694: 'Ce disque contient des données StartOS existantes.',
695: 'pour conserver vos données.',
696: 'pour supprimer',
697: 'Saisissez le mot de passe utilisé pour chiffrer cette sauvegarde.',
698: 'Plusieurs sauvegardes trouvées. Sélectionnez celle à restaurer.',
699: 'Sauvegardes',
700: 'Le disque sur lequel le système dexploitation StartOS sera installé.',
701: 'Le disque sur lequel vos données StartOS (services, paramètres, etc.) seront stockées. Il peut sagir du même disque que le système ou dun disque séparé.',
702: 'Après le transfert des données depuis ce disque, nessayez pas de démarrer dessus à nouveau en tant que serveur Start9. Cela peut entraîner des dysfonctionnements des services, une corruption des données ou une perte de fonds.',
703: 'Doit comporter au moins 12 caractères',
704: 'Doit comporter au maximum 64 caractères',
705: 'Les mots de passe ne correspondent pas',
706: 'Conserver',
707: 'Écraser',
708: 'Déverrouiller',
709: 'Disque',
710: 'Transférer',
711: 'La liste est vide',
} satisfies i18n

View File

@@ -597,5 +597,80 @@ export default {
627: 'Otwórz UI',
628: 'Skopiowano do schowka',
629: 'Instalowanie StartOS',
630: 'Wybierz swój język',
631: 'Wybierz układ klawiatury',
632: 'Klawiatura',
633: 'Wybierz tryb konfiguracji',
634: 'Rozpocznij od nowa',
635: 'Skonfiguruj zupełnie nowy serwer',
636: 'Przywróć z kopii zapasowej',
637: 'Przywróć dane StartOS z zaszyfrowanej kopii zapasowej',
638: 'Przenieś dane z istniejącego dysku danych StartOS',
639: 'Wybierz dyski',
640: 'Nie znaleziono dysków. Podłącz dysk i kliknij Odśwież.',
641: 'Dysk systemowy',
642: 'Dysk danych',
643: 'Wykryto dane StartOS',
644: 'Dane na dysku systemowym mogą zostać nadpisane.',
645: 'Twoje dane StartOS na dysku danych zostaną zachowane.',
646: 'Dane na tym dysku zostaną nadpisane.',
647: 'Dane na obu dyskach zostaną nadpisane.',
648: 'Wybierz kopię zapasową',
649: 'Wybierz kopię zapasową StartOS do przywrócenia',
650: 'Otwórz kopię zapasową sieciową',
651: 'Kopie zapasowe fizyczne',
652: 'Brak fizycznych kopii zapasowych',
653: 'Połącz folder sieciowy',
654: 'Wybierz kopię zapasową sieciową',
655: 'Odblokuj kopię zapasową',
656: 'Przenieś dane',
657: 'Wybierz dysk zawierający istniejące dane StartOS',
658: 'Wybierz dysk',
659: 'Nie znaleziono dysków danych StartOS',
660: 'Ustaw hasło główne',
661: 'Ustaw nowe hasło (opcjonalnie)',
662: 'Zadbaj o nie. Zapisz je.',
663: 'Pomiń, aby zachować istniejące hasło.',
664: 'Wprowadź hasło',
665: 'Potwierdź hasło',
666: 'Zakończ',
667: 'Rozpoczynanie konfiguracji',
670: 'Poczekaj 12 minuty i odśwież stronę',
672: 'Konfiguracja zakończona!',
673: 'Możesz odłączyć dysk kopii zapasowej',
674: 'Możesz odłączyć dysk transferowy',
675: 'http://start.local służył tylko do konfiguracji. Nie będzie już działać.',
676: 'Pobierz informacje adresowe',
677: 'Zawiera stały lokalny adres serwera oraz główny urząd certyfikacji (Root CA)',
678: 'Usuń nośnik USB',
679: 'Usuń instalacyjny nośnik USB z serwera',
680: 'Uruchom ponownie serwer',
681: 'Oczekiwanie na ponowne połączenie serwera',
682: 'Serwer jest ponownie online',
683: 'Uruchom ponownie serwer, aby zakończyć konfigurację',
684: 'Otwórz adres lokalny',
685: 'Przejdź do logowania',
686: 'Przejdź do ekranu logowania StartOS',
687: 'Serwer nie wrócił do trybu online. Sprawdź serwer i spróbuj uzyskać do niego dostęp ręcznie.',
691: 'To pole jest wymagane',
692: 'Nie udało się połączyć',
693: 'Nie można połączyć się z folderem sieciowym. Upewnij się, że (1) komputer docelowy jest podłączony do sieci LAN, (2) folder docelowy jest udostępniony oraz (3) nazwa hosta, ścieżka i dane logowania są poprawne.',
694: 'Ten dysk zawiera istniejące dane StartOS.',
695: 'aby zachować dane.',
696: 'aby odrzucić',
697: 'Wprowadź hasło użyte do zaszyfrowania tej kopii zapasowej.',
698: 'Znaleziono wiele kopii zapasowych. Wybierz, którą przywrócić.',
699: 'Kopie zapasowe',
700: 'Dysk, na którym zostanie zainstalowany system operacyjny StartOS.',
701: 'Dysk, na którym będą przechowywane dane StartOS (usługi, ustawienia itp.). Może to być ten sam dysk co systemowy lub oddzielny dysk.',
702: 'Po przeniesieniu danych z tego dysku nie próbuj ponownie uruchamiać z niego systemu jako serwer Start9. Może to spowodować nieprawidłowe działanie usług, uszkodzenie danych lub utratę środków.',
703: 'Musi mieć co najmniej 12 znaków',
704: 'Musi mieć maksymalnie 64 znaki',
705: 'Hasła nie są zgodne',
706: 'Zachowaj',
707: 'Nadpisz',
708: 'Odblokuj',
709: 'Dysk',
710: 'Przenieś',
711: 'Lista jest pusta',
} satisfies i18n