Jelajahi Sumber

Meta tags. Better multilanguage support.

Iñigo Valentin 10 bulan lalu
induk
melakukan
ae59d5c7e3

+ 5 - 1
frontend/package.json

@@ -4,8 +4,12 @@
   "author": "Iñigo Valentin",
   "authorURL": "https://inigovalentin.com",
   "sourceSite": "Github",
-  "sourceURL": "https://github.com/InigoValentin/LeatherWeb",
+  "sourceURL": "https://github.com/InigoValentin/leather.inigovalentin.com",
   "license": "GPLv3",
+  "languages":{
+    "available": "es|en|eu",
+    "default": "es"
+  },
   "scripts": {
     "ng": "ng",
     "start": "ng serve",

TEMPAT SAMPAH
frontend/public/img/logo/leather.png


+ 50 - 6
frontend/src/app/app.ts

@@ -1,9 +1,12 @@
 import { Component, ViewEncapsulation, inject } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
+import { RouterOutlet, ActivatedRoute } from '@angular/router';
 import { TranslateService, TranslatePipe, TranslateDirective } from '@ngx-translate/core';
+import { Meta } from '@angular/platform-browser';
+import { author, languages} from '../../package.json';
 import { Header } from './header/header';
 import { Footer } from './footer/footer';
 
+
 @Component({
   selector: 'app-root',
   imports: [RouterOutlet, Header, Footer],
@@ -15,10 +18,51 @@ export class App {
     
     private translate = inject(TranslateService);
     
-    constructor(){
-        this.translate.addLangs(['en', 'eu']);
-        this.translate.setFallbackLang('es');
-        // TODO: Get language from browset if not in storage
-        this.translate.use(localStorage.getItem('language') || this.translate.getFallbackLang() || 'es');
+    author: string = author;
+    private languages: any = languages;
+
+    /**
+     * Selects the best language to serve the page in.
+     * 
+     * It considers available languages, browser languages, query parameters, local storage...
+     * 
+     * @return Two letter language code of the language to show the page in.
+     */
+    private selectLanguage(): string{
+        
+        let available: String[] = this.languages.available.split("|");
+        // If the language is set as a request parameter and its valid, use it.
+        const queryLang = new URLSearchParams(window.location.search).get('lang');
+        console.log("QUERY LANG: " + queryLang);
+        if (queryLang && available.indexOf(queryLang.substring(0, 2).toLowerCase()) != -1)
+            return queryLang.substring(0, 2).toLowerCase();
+
+        // If the language has been previously set and a valid one is its in local storage, done.
+        if (available.indexOf("" + localStorage.getItem('language')) != -1)
+            return "" + localStorage.getItem('language');
+        
+        // If the language is not set, loop the browser accepted languages.
+        // When there is a match with the app available languages, return it.
+        for (let l of navigator.languages){
+            if ( l.length >= 2 && available.indexOf(l.substring(0, 2).toLowerCase()) != -1)
+                return l.substring(0, 2).toLowerCase();
+        }
+        
+        // If everything else failed, return the default language.
+        return this.languages.default;
+    }
+    
+    constructor(private metaService: Meta, private route: ActivatedRoute){
+        
+        this.translate.addLangs(this.languages.available.split("|"));
+        this.translate.setFallbackLang(this.languages.default);
+        // Detect the best language.
+        const lang: string = this.selectLanguage()
+        this.translate.use(lang);
+        localStorage.setItem('language', lang)
+        
+        // Set meta tags
+        this.metaService.addTag({ property: 'author', author });
+
     }
 }

+ 1 - 1
frontend/src/app/footer/footer.ts

@@ -15,8 +15,8 @@ export class Footer{
     license: string = license;
     
     languages = [
-        { code: 'en', name: 'English' },
         { code: 'es', name: 'Español' },
+        { code: 'en', name: 'English' },
         { code: 'eu', name: 'Euskara' },
     ];
 

+ 14 - 4
frontend/src/app/home/home.ts

@@ -1,5 +1,5 @@
 import { Component, OnInit, inject } from '@angular/core';
-import { Title } from '@angular/platform-browser';
+import { Meta, Title } from '@angular/platform-browser';
 import { TranslateService, _ } from '@ngx-translate/core';
 import { ProjectService } from '../service/project-service';
 import { ProfileService } from '../service/profile-service';
@@ -20,7 +20,7 @@ export class Home implements OnInit {
 
     constructor(
       private projectService: ProjectService, private profileService: ProfileService,
-      private titleService: Title
+      private titleService: Title, private metaService: Meta
     ){
         this.utilService = new UtilService()
         this.translate.use("" + localStorage.getItem("language"));
@@ -31,9 +31,19 @@ export class Home implements OnInit {
         this.profileService.getProfile().subscribe(data => { this.profile = data; });
         this.startInterval();
         this.translate.use("" + localStorage.getItem("language"));
-        //this.translate.use
+        // Set meta tags
+        const url: string = window.location.protocol + "//" + window.location.host;
+        this.metaService.addTag({ property: 'canonical', content: url });
+        this.metaService.addTag({ property: 'og:url', content: url });
+        this.metaService.addTag({ property: 'og:image', content: url + '/img/logo/leather.png' });
         this.translate.get(_('SITE.TITLE')).subscribe((res: string) => {
-            this.titleService.setTitle(res)
+            this.titleService.setTitle(res);
+            this.metaService.addTag({ property: 'og:title', content: res});
+            this.metaService.addTag({ property: 'title', content: res});
+        });
+        this.translate.get(_('SITE.DESCRIPTION')).subscribe((res: string) => {
+            this.metaService.addTag({ property: 'og:description', content: res});
+            this.metaService.addTag({ property: 'description', content: res});
         });
     }
   

+ 33 - 5
frontend/src/app/project/project.ts

@@ -1,8 +1,8 @@
 import { Component, inject } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
-import { Title } from '@angular/platform-browser';
+import { Title, Meta } from '@angular/platform-browser';
 import { ProjectService } from '../service/project-service';
-import { TranslateService } from '@ngx-translate/core';
+import { TranslateService, _ } from '@ngx-translate/core';
 import { UtilService } from '../service/util-service';
 import { ProjectModel } from '../model/project';
 import { environment } from '../../environments/environment';
@@ -30,7 +30,7 @@ export class Project {
 
     constructor(
       private route: ActivatedRoute, private projectService:
-      ProjectService, private titleService: Title
+      ProjectService, private titleService: Title, private metaService: Meta
     ){
         this.utilService = new UtilService();
     }
@@ -41,9 +41,37 @@ export class Project {
         this.projectService.getProject("" + id).subscribe(data => {
             this.project = data;
             this.maxIndex = this.project.images.length;
-            this.titleService.setTitle(
-              this.project.title + " - " + this.translate.instant('SITE.TITLE')
+            
+            // Set meta tags
+            const siteUrl: string = window.location.protocol + "//" + window.location.host;
+            const projectUrl: string = siteUrl + '/projects' + this.project.permalink;
+            this.metaService.addTag({ property: 'canonical', content: projectUrl });
+            this.metaService.addTag({ property: 'og:url', content: projectUrl });
+            this.metaService.addTag(
+              { property: 'og:description', content: this.project.description}
             );
+            this.metaService.addTag(
+              { property: 'description', content: this.project.description}
+            );
+            if (this.project.images.length > 0){
+                this.metaService.addTag(
+                  { property: 'og:image', content: this.apiURL + this.project.images[0].path }
+                );
+            }
+            else{
+                this.metaService.addTag(
+                  { property: 'og:image', content: siteUrl + '/img/logo/leather.png' }
+                );
+            }
+            this.translate.get(_('SITE.TITLE')).subscribe((res: string) => {
+                this.titleService.setTitle(this.project?.title + " - " + res);
+                this.metaService.addTag(
+                  { property: 'title', content: this.project?.title + " - " + res }
+                );
+                this.metaService.addTag(
+                  { property: 'og:title', content: this.project?.title + " - " + res }
+                );
+            });
         });
     }
 

+ 0 - 1
frontend/src/index.html

@@ -2,7 +2,6 @@
 <html lang="en">
 <head>
   <meta charset="utf-8">
-  <title>Frontend</title>
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">