diff --git a/.vscode/settings.json b/.vscode/settings.json
index b3b9243..a1acd47 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
- "prettier.tabWidth": 2
+ "editor.tabSize": 2
}
\ No newline at end of file
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 2c3d4eb..990c5d5 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,3 +1,6 @@
-
+
- @for(item of elements; track $index) {
-
+ @for(item of elements_data; track $index) {
+
+
}
diff --git a/src/app/components/text_list/text_list.component.scss b/src/app/components/text_list/text_list.component.scss
index cb41263..4ec5585 100644
--- a/src/app/components/text_list/text_list.component.scss
+++ b/src/app/components/text_list/text_list.component.scss
@@ -3,85 +3,17 @@
flex-direction: column;
gap: 3rem;
align-items: center;
- textarea {
- height: fit-content;
- min-height: 3rem;
- line-height: 3rem;
- border-radius: 8px;
- color: #efdee0;
- outline: none;
- padding-inline: 2rem 1rem;
- background-color: transparent;
- border: 2px solid #e4bdc3;
- word-wrap: break-word;
- overflow-x: hidden;
- resize: none;
- overflow-y: hidden;
- &:focus {
- border: 2px solid #efdee0;
- }
- font-size: 1rem;
- font-weight: inherit;
- }
margin-inline: 2rem;
}
-.english-text {
- color: #efdee0;
- border: 2px solid #e4bdc3;
- word-wrap: break-word;
- border-radius: 8px;
- padding-inline: 2rem 1rem;
- line-height: 3rem;
- background-color: transparent;
-}
-
-.element {
- display: flex;
- background-color: #413738;
- padding: 3rem 5rem;
- border-radius: 30px;
- flex-direction: row;
- width: 100%;
- max-width: 1200px;
- align-items: center;
- gap: 2rem;
- justify-content: space-between;
- h2 {
- color: #efdee0;
- }
- .fields {
- display: flex;
- flex-direction: column;
- gap: 1rem;
- width: 100%;
- max-width: 1200px;
- }
-}
-
-@media (max-width: 768px) {
- .element {
- flex-direction: column;
- }
-}
-
h1 {
color: #efdee0;
text-align: center;
margin: 1rem 2rem;
}
-
-.send-translate-btn {
- outline: none;
- border: none;
- cursor: pointer;
- background-color: #5b3f45;
- padding: 1em 1.5em;
- color: #f5f6fa;
- border-radius: 15px;
- transition: ease-in-out 0.2s;
- margin: 2rem;
- &:hover {
- transform: scale(1.2);
- }
+app-translate-block {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
}
diff --git a/src/app/components/text_list/text_list.component.ts b/src/app/components/text_list/text_list.component.ts
index 53c7cd3..2cf02c4 100644
--- a/src/app/components/text_list/text_list.component.ts
+++ b/src/app/components/text_list/text_list.component.ts
@@ -1,38 +1,67 @@
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
-import { Component, Input } from '@angular/core';
+import { ChangeDetectorRef, Component, Input } from '@angular/core';
+import { TranslateBlockComponent } from '../translate_block/translate_block.component';
+import { TranslateData } from './text_list.dto';
@Component({
selector: 'app-text-list',
templateUrl: './text_list.component.html',
styleUrls: ['./text_list.component.scss'],
standalone: true,
- imports: [CommonModule],
+ imports: [CommonModule, TranslateBlockComponent],
})
export class TextListComponent {
- constructor(private http: HttpClient) {}
- private _elements: string[] = [];
- translated_text: string = '';
+ constructor(private http: HttpClient, private changeDetectionRef: ChangeDetectorRef) {
+ const data = localStorage.getItem('translations');
+ if (data) {
+ this.elements_data = JSON.parse(data);
+ }
+ }
+ elements_data: TranslateData[] = [];
@Input() set elements(el: string[]) {
- this._elements = el;
+ this.elements_data = el.map((item) => ({ english_text: item, translated_text: '' }));
+ localStorage.setItem('translations', JSON.stringify(this.elements_data));
}
get elements() {
- return this._elements;
- }
- autoScroll($event: Event) {
- const target = $event.target as HTMLTextAreaElement;
- target.style.height = '3rem';
- target.style.height = target.scrollHeight + 'px';
+ return this.elements_data.map((item) => item.english_text);
}
- sendToTranslate($text: string) {
+ sendToTranslate($text: string, $index: number) {
+ if (!$text) {
+ return;
+ }
+ if (this.elements_data[$index].translated_text && !confirm('Are you sure you want to override the translation?')) {
+ return;
+ }
+ console.log('translated');
$text = encodeURIComponent($text);
- console.log(this.elements);
- //TODO: говно какое-та не хочет отправлять целиком
this.http
.get(`https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=ru&dt=t&q=` + $text)
- .subscribe({ next: (data: any) => (this.translated_text = data[0][0][0]) });
+ .subscribe({
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ next: (data: any) => {
+ this.elements_data[$index].translated_text = data[0][0][0];
+ localStorage.setItem('translations', JSON.stringify(this.elements_data));
+ this.changeDetectionRef.detectChanges();
+ },
+ error: (error) => {
+ alert(error);
+ console.error(error);
+ },
+ });
+ }
+
+ typeTranslation($event: Event, $index: number) {
+ const target = $event.target as HTMLDivElement;
+ if (target) {
+ this.elements_data[$index].translated_text = target.textContent || '[]';
+ localStorage.setItem('translations', JSON.stringify(this.elements_data));
+ target.style.height = '3rem';
+ target.style.height = target.scrollHeight + 'px';
+ // this.changeDetectionRef.detectChanges();
+ }
}
}
diff --git a/src/app/components/text_list/text_list.dto.ts b/src/app/components/text_list/text_list.dto.ts
new file mode 100644
index 0000000..588f7cb
--- /dev/null
+++ b/src/app/components/text_list/text_list.dto.ts
@@ -0,0 +1,4 @@
+export interface TranslateData {
+ english_text: string;
+ translated_text: string;
+}
diff --git a/src/app/components/translate_block/translate_block.component.html b/src/app/components/translate_block/translate_block.component.html
new file mode 100644
index 0000000..64db149
--- /dev/null
+++ b/src/app/components/translate_block/translate_block.component.html
@@ -0,0 +1,16 @@
+
+
{{ index + 1 }}
+
+
{{ item.english_text }}
+
+
+
+
+
+
diff --git a/src/app/components/translate_block/translate_block.component.scss b/src/app/components/translate_block/translate_block.component.scss
new file mode 100644
index 0000000..8a402d4
--- /dev/null
+++ b/src/app/components/translate_block/translate_block.component.scss
@@ -0,0 +1,82 @@
+.translated-text {
+ border-radius: 8px;
+ height: fit-content;
+ color: #efdee0;
+ outline: none;
+ padding-inline: 2rem 1rem;
+ background-color: transparent;
+ border: 2px solid #e4bdc3;
+ font-size: 1rem;
+ font-weight: inherit;
+ &:focus {
+ border: 2px solid #efdee0;
+ }
+ textarea {
+ resize: none;
+ width: 100%;
+ height: fit-content;
+ background-color: transparent;
+ border: none;
+ outline: none;
+ color: #efdee0;
+ font-size: 1rem;
+ font-weight: inherit;
+ line-height: 3rem;
+
+ word-wrap: break-word;
+ }
+}
+
+.english-text {
+ color: #efdee0;
+ border: 2px solid #e4bdc3;
+ word-wrap: break-word;
+ border-radius: 8px;
+ padding-inline: 2rem 1rem;
+ line-height: 3rem;
+ background-color: transparent;
+}
+
+.element {
+ display: flex;
+ background-color: #413738;
+ padding: 3rem 5rem;
+ border-radius: 30px;
+ flex-direction: row;
+ width: 100%;
+ max-width: 1200px;
+ align-items: center;
+ gap: 2rem;
+ justify-content: space-between;
+ h2 {
+ color: #efdee0;
+ }
+ .fields {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ width: 100%;
+ max-width: 1200px;
+ }
+}
+
+@media (max-width: 768px) {
+ .element {
+ flex-direction: column;
+ }
+}
+
+.send-translate-btn {
+ outline: none;
+ border: none;
+ cursor: pointer;
+ background-color: #5b3f45;
+ padding: 1em 1.5em;
+ color: #f5f6fa;
+ border-radius: 15px;
+ transition: ease-in-out 0.2s;
+ margin: 2rem;
+ &:hover {
+ transform: scale(1.2);
+ }
+}
diff --git a/src/app/components/translate_block/translate_block.component.ts b/src/app/components/translate_block/translate_block.component.ts
new file mode 100644
index 0000000..78eab94
--- /dev/null
+++ b/src/app/components/translate_block/translate_block.component.ts
@@ -0,0 +1,31 @@
+import { CommonModule } from '@angular/common';
+import { Component, ElementRef, Input, ViewChild } from '@angular/core';
+import { TranslatePipe } from 'src/app/pipes/translate.pipe';
+import { TranslateData } from '../text_list/text_list.dto';
+
+@Component({
+ selector: 'app-translate-block',
+ templateUrl: './translate_block.component.html',
+ styleUrls: ['./translate_block.component.scss'],
+ standalone: true,
+ imports: [CommonModule],
+ providers: [TranslatePipe],
+})
+export class TranslateBlockComponent {
+ @ViewChild('translatedText') translatedText: ElementRef
| null = null;
+ @Input() item: TranslateData = { english_text: '', translated_text: '' };
+ @Input() index = 0;
+
+ constructor(private translatePipe: TranslatePipe) {}
+ async sendToTranslate() {
+ const text = await this.translatePipe.transform(this.item.english_text);
+ this.item.translated_text = text;
+ }
+ typeTranslation() {
+ if (this.translatedText) {
+ const element = this.translatedText.nativeElement;
+ element.setAttribute('style', 'height: 3px;');
+ element.setAttribute('style', 'height:' + element.scrollHeight + 'px; overflow-y:hidden;');
+ }
+ }
+}
diff --git a/src/app/components/upload_btn/upload_btn.component.ts b/src/app/components/upload_btn/upload_btn.component.ts
index e0fa549..8af4024 100644
--- a/src/app/components/upload_btn/upload_btn.component.ts
+++ b/src/app/components/upload_btn/upload_btn.component.ts
@@ -25,6 +25,7 @@ export class UploadBtnComponent {
const reader = new FileReader();
reader.onload = () => {
this.fileLoaded.emit(reader.result as string);
+ target.value = '';
};
reader.readAsText(file);
}
diff --git a/src/app/lib/translater.ts b/src/app/lib/translater.ts
new file mode 100644
index 0000000..30a8184
--- /dev/null
+++ b/src/app/lib/translater.ts
@@ -0,0 +1,17 @@
+import { HttpClient } from '@angular/common/http';
+import { firstValueFrom } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+export async function translate(text: string, http: HttpClient): Promise {
+ const response = await firstValueFrom(
+ http
+ .get(
+ `https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=ru&dt=t&q=` + encodeURIComponent(text),
+ )
+ .pipe(
+ map((data: any) => data[0][0][0]), // Assuming the response structure from the API
+ ),
+ );
+
+ return response;
+}
diff --git a/src/app/pipes/translate.pipe.ts b/src/app/pipes/translate.pipe.ts
new file mode 100644
index 0000000..e4400b3
--- /dev/null
+++ b/src/app/pipes/translate.pipe.ts
@@ -0,0 +1,10 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { TranslateService } from '../services/translate.service';
+
+@Pipe({ name: 'translate', standalone: true, pure: false })
+export class TranslatePipe implements PipeTransform {
+ constructor(private translateService: TranslateService) {}
+ transform(text: string) {
+ return this.translateService.translate(text);
+ }
+}
diff --git a/src/app/services/translate.service.ts b/src/app/services/translate.service.ts
new file mode 100644
index 0000000..95d0dd8
--- /dev/null
+++ b/src/app/services/translate.service.ts
@@ -0,0 +1,27 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+
+@Injectable({ providedIn: 'root' })
+export class TranslateService {
+ constructor(private http: HttpClient) {}
+ translate(text: string): Promise {
+ return new Promise((resolve) => {
+ this.http
+ .get(
+ 'https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=ru&dt=t&q=' +
+ encodeURIComponent(text),
+ )
+ .subscribe({
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ next: (response: any) => {
+ console.log(response);
+ resolve(response[0][0][0]);
+ },
+ error: (error) => {
+ console.error(error);
+ resolve('');
+ },
+ });
+ });
+ }
+}