Mise en place de l'anglais comme deuxième langue pour l'application
Some checks failed
Build & Push Images / build (brain) (push) Has been cancelled
Build & Push Images / build (core) (push) Has been cancelled
Build & Push Images / build (web) (push) Has been cancelled
Build & Push Images / build-switcher (push) Has been cancelled

This commit is contained in:
2026-06-14 16:24:05 +02:00
parent 6e75326779
commit af3a6d443c
198 changed files with 7801 additions and 1720 deletions

View File

@@ -2,8 +2,7 @@
@if (rooms.length === 0) {
<p class="rooms-empty">
Aucune pièce. La scène se comporte comme un beat narratif classique.
Ajoutez une première pièce pour la convertir en lieu explorable (donjon, crypte…).
{{ 'roomsEditor.empty' | translate }}
</p>
}
@@ -21,16 +20,16 @@
[ngModel]="r.name"
(ngModelChange)="patch(r, { name: $event })"
(click)="$event.stopPropagation()"
placeholder="Nom de la pièce" />
[placeholder]="'roomsEditor.roomNamePlaceholder' | translate" />
<input type="number" class="room-floor-input"
[ngModel]="r.floor"
(ngModelChange)="patch(r, { floor: $event === null || $event === '' ? null : +$event })"
(click)="$event.stopPropagation()"
placeholder="Ét." title="Étage (0 = RdC)" />
[placeholder]="'roomsEditor.floorPlaceholder' | translate" [title]="'roomsEditor.floorTitle' | translate" />
<div class="room-actions" (click)="$event.stopPropagation()">
<button type="button" class="btn-icon" (click)="moveUp(r)" [disabled]="i === 0" title="Monter"></button>
<button type="button" class="btn-icon" (click)="moveDown(r)" [disabled]="i === rooms.length - 1" title="Descendre"></button>
<button type="button" class="btn-icon-danger" (click)="removeRoom(r)" title="Supprimer la pièce">
<button type="button" class="btn-icon" (click)="moveUp(r)" [disabled]="i === 0" [title]="'roomsEditor.moveUp' | translate"></button>
<button type="button" class="btn-icon" (click)="moveDown(r)" [disabled]="i === rooms.length - 1" [title]="'roomsEditor.moveDown' | translate"></button>
<button type="button" class="btn-icon-danger" (click)="removeRoom(r)" [title]="'roomsEditor.removeRoom' | translate">
<lucide-icon [img]="Trash2" [size]="14"></lucide-icon>
</button>
</div>
@@ -39,14 +38,14 @@
@if (isExpanded(r.id)) {
<div class="room-body">
<div class="field">
<label>Description (lue/résumée aux joueurs)</label>
<label>{{ 'roomsEditor.descriptionLabel' | translate }}</label>
<textarea rows="3"
[ngModel]="r.description"
(ngModelChange)="patch(r, { description: $event })"
placeholder="Atmosphère, ce que voient les PJ en entrant…"></textarea>
[placeholder]="'roomsEditor.descriptionPlaceholder' | translate"></textarea>
</div>
<div class="field">
<label>Ennemis du bestiaire</label>
<label>{{ 'roomsEditor.bestiaryLabel' | translate }}</label>
<app-enemy-link-picker
[value]="r.enemyIds ?? []"
[availableEnemies]="availableEnemies"
@@ -56,41 +55,41 @@
</div>
<div class="field-row">
<div class="field">
<label>Ennemis / créatures / boss (texte libre)</label>
<label>{{ 'roomsEditor.enemiesLabel' | translate }}</label>
<textarea rows="3"
[ngModel]="r.enemies"
(ngModelChange)="patch(r, { enemies: $event })"
placeholder="2 gobelins, 1 ogre boss (PV 60, AC 14)…"></textarea>
[placeholder]="'roomsEditor.enemiesPlaceholder' | translate"></textarea>
</div>
<div class="field">
<label>Loot / trésors</label>
<label>{{ 'roomsEditor.lootLabel' | translate }}</label>
<textarea rows="3"
[ngModel]="r.loot"
(ngModelChange)="patch(r, { loot: $event })"
placeholder="50 po, potion de soin, clé en argent…"></textarea>
[placeholder]="'roomsEditor.lootPlaceholder' | translate"></textarea>
</div>
</div>
<div class="field-row">
<div class="field">
<label>Pièges / dangers</label>
<label>{{ 'roomsEditor.trapsLabel' | translate }}</label>
<textarea rows="2"
[ngModel]="r.traps"
(ngModelChange)="patch(r, { traps: $event })"
placeholder="Trappe (DC 15 Perception), flèches empoisonnées…"></textarea>
[placeholder]="'roomsEditor.trapsPlaceholder' | translate"></textarea>
</div>
<div class="field">
<label>Notes MJ (privé)</label>
<label>{{ 'roomsEditor.gmNotesLabel' | translate }}</label>
<textarea rows="2"
[ngModel]="r.gmNotes"
(ngModelChange)="patch(r, { gmNotes: $event })"
placeholder="Le boss connaît les PJ par leur nom, indice…"></textarea>
[placeholder]="'roomsEditor.gmNotesPlaceholder' | translate"></textarea>
</div>
</div>
<!-- Branches inter-pièces -->
<div class="field">
<label>
<lucide-icon [img]="GitBranch" [size]="14"></lucide-icon>
Sorties / portes vers d'autres pièces
{{ 'roomsEditor.exitsLabel' | translate }}
</label>
@if ((r.branches?.length ?? 0) > 0) {
<ul class="branch-list">
@@ -99,14 +98,14 @@
<input type="text" class="branch-label"
[ngModel]="b.label"
(ngModelChange)="updateBranch(r, bi, { label: $event })"
placeholder="Porte nord" />
[placeholder]="'roomsEditor.branchLabelPlaceholder' | translate" />
<span class="branch-arrow"></span>
<select class="branch-target"
[ngModel]="b.targetRoomId"
(ngModelChange)="updateBranch(r, bi, { targetRoomId: $event })"
[disabled]="otherRooms(r).length === 0">
@if (otherRooms(r).length === 0) {
<option value="">(aucune autre pièce)</option>
<option value="">{{ 'roomsEditor.noOtherRoom' | translate }}</option>
}
@for (o of otherRooms(r); track o) {
<option [value]="o.id">{{ o.name }}</option>
@@ -115,7 +114,7 @@
<input type="text" class="branch-condition"
[ngModel]="b.condition"
(ngModelChange)="updateBranch(r, bi, { condition: $event })"
placeholder="Condition (optionnelle)" />
[placeholder]="'roomsEditor.branchConditionPlaceholder' | translate" />
<button type="button" class="btn-icon-danger" (click)="removeBranch(r, bi)">
<lucide-icon [img]="X" [size]="14"></lucide-icon>
</button>
@@ -127,7 +126,7 @@
(click)="addBranch(r)"
[disabled]="otherRooms(r).length === 0">
<lucide-icon [img]="Plus" [size]="13"></lucide-icon>
Ajouter une sortie
{{ 'roomsEditor.addExit' | translate }}
</button>
</div>
</div>
@@ -139,7 +138,7 @@
<button type="button" class="btn-primary" (click)="addRoom()">
<lucide-icon [img]="Plus" [size]="14"></lucide-icon>
Ajouter une pièce
{{ 'roomsEditor.addRoom' | translate }}
</button>
</div>

View File

@@ -2,6 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { LucideAngularModule, Plus, Trash2, ChevronDown, ChevronUp, GitBranch, X } from 'lucide-angular';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { Room, RoomBranch } from '../../services/campaign.model';
import { Enemy } from '../../services/enemy.model';
import { EnemyLinkPickerComponent } from '../enemy-link-picker/enemy-link-picker.component';
@@ -17,7 +18,7 @@ import { EnemyLinkPickerComponent } from '../enemy-link-picker/enemy-link-picker
*/
@Component({
selector: 'app-rooms-editor',
imports: [FormsModule, LucideAngularModule, EnemyLinkPickerComponent],
imports: [FormsModule, LucideAngularModule, EnemyLinkPickerComponent, TranslatePipe],
templateUrl: './rooms-editor.component.html',
styleUrls: ['./rooms-editor.component.scss']
})
@@ -30,6 +31,8 @@ export class RoomsEditorComponent {
@Input() campaignId = '';
@Output() roomsChange = new EventEmitter<Room[]>();
constructor(private translate: TranslateService) {}
readonly Plus = Plus;
readonly Trash2 = Trash2;
readonly ChevronDown = ChevronDown;
@@ -57,7 +60,7 @@ export class RoomsEditorComponent {
: 0;
const newRoom: Room = {
id: this.newId(),
name: `Salle ${this.rooms.length + 1}`,
name: this.translate.instant('roomsEditor.defaultRoomName', { n: this.rooms.length + 1 }),
order: nextOrder,
branches: []
};
@@ -89,7 +92,7 @@ export class RoomsEditorComponent {
addBranch(room: Room): void {
const others = this.rooms.filter(r => r.id !== room.id);
const branch: RoomBranch = {
label: 'Porte',
label: this.translate.instant('roomsEditor.defaultBranchLabel'),
targetRoomId: others[0]?.id ?? '',
condition: ''
};