HTML5-Tutorium: JavaScript: Hello World Vue 05
Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:
Korrektheit: 3 (zu größeren Teilen überprüft) |
Umfang: 4 (unwichtige Fakten fehlen) |
Quellenangaben: 3 (wichtige Quellen vorhanden) |
Quellenarten: 5 (ausgezeichnet) |
Konformität: 3 (gut) |
Inhalt | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5 | Teil 6 | Vue 1 | Vue 2 | Vue 3 | Vue 4 | Vue 5
Musterlösung
Git-Repository, git checkout v05
, ... v05a
, ... v05b
, ... v05c
Anwendungsfälle (Use Cases)
Gegenüber dem ersten, zweiten und dritten Teil des Vue-Tutoriums ändern sich die die Anwendungsfälle zunächst nicht. Die Anwendung leistet also genau dasselbe wie zuvor.
Zum Schluss wird die Anwendung allerdings erweitert. Die Begrüßung erfolgt in der vom Browser als Favorit angegebenen Sprache, sofern die Begrüßungsdaten für diese Sprache hinterlegt wurden. Anderenfalls erfolgt die Begrüßung ein der Defaultsprache.
Aufgabe
Aufgabe: Konfigurieren und internationalisieren Sie die Anwendung mit Hilfe von dynamischen JSON-Dateien.
Erstellen eines neuen Projektzweigs
Erstellen Sie einen neuen Projektzweig (branch) innerhalb von hello_world_vue
und fügen Sie das Package uuid
hinzu:
git checkout v04 # Wechsle in den Branch v04
git checkout -b v05 # Klone v04 in einen neuen Branch v05
npm i
Kofigurationsdateien
Hauptkonfigurationsdatei
Die folgende Datei dient zur statischen Konfiguration der Anwendung. Der Inhalt wird in die App fest eingebunden und kann in der laufenden Anwendung ohnen einen Rebuild nicht geändert werden.
// src/json/config.json
{ "startSection": "form" }
Internationalisierungsdateien
Die folgenden Dateien sollen zunächst statisch eingelesen werden. Sie dienen der Internationalisierung (internationalization = i..................n = i18n).
// src/json/i18n_de.json
{ "phrases":
{ "hello": "Hallo, $1!"
},
"dictionary":
{ "stranger": "Fremder",
"askName": "Wie heißen Sie?",
"welcome": "Willkommen zu Web-Programmierung!",
"buttonReset": "Reset",
"buttonSayHello": "Begrüßung"
}
}
// src/json/i18n_en.json
{ "phrases":
{ "hello": "Hello, $1!"
},
"dictionary":
{ "stranger": "Stranger",
"askName": "What's your name?",
"welcome": "Welcome to Web Programing!",
"buttonReset": "reset",
"buttonSayHello": "say hello"
}
}
Er können jederzeit I18n-Dateien für weitere Sprachen definiert werden.
Statische JSON-Dateien (v05)
Initialisierung von StoreSession.js
mit Hilfe einer JSON-Datei
Die JSON-Datei config.json
wird von StoreSession.js
statisch eingelesen, um den zugehörigen Store zu initialisieren. Fügen Sie
folgenden Import-Befehl in diese Datei ein:
import config from '@/json/config.json'
An dieser Stelle würde ich keine Vite-Alias '/json'
definieren, sondern die Schreibweise
'@/json/...'
beibehalten. Der Grund ist, dass die JSON-Dateien später dynamisch aus dem Public-Bereich geladen werden sollen und der JSON-Ordner dort unter dem Namen '/json'
zu finden sein wird.
Der statische Import von JSON-Dateien ist im ECMAScript-Standard nicht vorgesehen. Eigentlich müssen JSON-Dateien immer asynchron mit Hilfe spezieller AJAX-Anweisungen geladen werden.
Allerdings ist der statische Import in Transcodern wie webpack, vite etc. möglich. Hierbei wird der Import-Befehl bereits zur „Übersetzungszeit“ und nicht erst zur Laufzeit ausgeführt. Das heißt, der Inhalt der JSON-Datei wird in den erzeugten JavaScript-Code direkt eingefügt.
Nun kann der Name der Start-Section initialisiert werden:
const
section = ref(config.startSection),
...
Die Initialisierung von StoreSession erfolgt bislang in der Datei HelloWorld.vue
mittels der Funition session.init
. Entfernen Sie in der Date0 StoreSession.js
die Init-Funktion und in der Datei HelloWorld.vue
den zugehörigen Aufruf der Init-Funktion.
Sie können nun auch noch die Funktion "init" aus der Datei StoreSession.js entfernen, da die Initialisierung jetzt über JSON erfolgt.
StoreGreeting.js
Die Webanwendung soll internationalisiert werden. Dazu muss StoreGreeting.js
um Internationalisierungstexte erweitert werden.
Die Konstante config
wird wie in StoreSession.js
definiert.
In config.i18n
sind Internationalisierungstexte enthalten. (Sie wurden in der Datei main.js
separat geladen und eingefügt.) Die Datei StoreGreeting.js
und die Komponenten, die diesen Store verwenden, müssen entsprechend erweitert werden.
Beachten Sie, dass f_hello
gegenüber den früheren Implementierungen einen leeren Namen
durch den Namen
dictionary.stranger
ersetzt. (Isabella, danke für den Tipp.)
Beachten Sie außerdem, dass f_hello
früher sayHello
hieß. Allerdings gibt es in SectionHello.vue
eine Funktion mit gleichem Namen, aber anderer Funktionalität. Um Verwechslungen zu vermeiden, habe ich die (Hilfs-)Funktion in StoreGreeting.js
umbenannt.
// src/store/StoreGreeting.js
import { defineStore } from 'pinia'
import { reactive, ref, computed, readonly } from 'vue'
import config from '@/json/i18n_de.json'
const
storeGreeting =
defineStore
( 'greeting',
() =>
{ const
phrases =
reactive(config.phrases),
dictionary =
reactive(config.dictionary),
name =
ref(''),
sayHello =
p_name => phrases.hello.replace('$1', p_name === '' ? dictionary.stranger : p_name),
//p_name => phrases?.hello?.replace('$1', p_name === '' ? dictionary.stranger : p_name),
helloStranger =
computed(() => sayHello(dictionary.stranger)),
hello =
computed(() => sayHello(name.value))/*,
askName =
computed(() => dictionary.askName),
welcome =
computed(() => dictionary.welcome),
buttonReset =
computed(() => dictionary.buttonReset),
buttonSayHello =
computed(() => dictionary.buttonSayHello)
*/
return { name, helloStranger, hello, dictionary: readonly(dictionary)
/*, askName, welcome, buttonReset, buttonSayHello */
}
}
)
export default storeGreeting
Die Methoden askName, welcome etc. würden die Verwendung des Stores einfacher machen, blähen aber die Datei stark auf, wenn i18n viele Begriffe enthält.
SectionHello.vue
Die Datei SectionHello.vue
muss an die Internationalisierung angepasst werden, indem alle deutschen Wörter und Phrasen ersetzt durch Zugriffe auf den StoreGreeting
ersetzt werden.
<!-- src/section/SectionHello.vue -->
<script setup>
import storeSession from '/store/StoreSession'
import storeGreeting from '/store/StoreGreeting'
const
session = storeSession(),
greeting = storeGreeting(),
dictionary = greeting.dictionary
</script>
<template>
<!-- const in code: 'hello' should be passed via a prop -->
<section v-if="session.section==='hello'">
<h1>{{greeting.hello}}</h1>
<p>{{dictionary.welcome}}</p>
</section>
</template>
<style scoped>
@import '/css/component/section/SectionHello.css';
</style>
SectionForm.vue
Die Datei SectionHello.vue
muss auf dieselbe Weise aktualisiert werden. Allerdings benötig man ein paar mehr Konstanten.
<!-- src/section/SectionForm.vue -->
<script setup>
import FormButton from '/component/form/FormButton.vue'
import FormTextfield from '/component/form/FormTextfield.vue'
import storeSession from '/store/StoreSession'
import storeGreeting from '/store/StoreGreeting'
const
session = storeSession(),
greeting = storeGreeting(),
dictionary = greeting.dictionary,
sayHello = () => session.section = 'hello'
</script>
<template>
<!-- const in code: 'form' should be passed via a prop -->
<section v-if="session.section==='form'">
<h1>{{greeting.helloStranger}}</h1>
<form>
<div>
<FormTextfield :label="dictionary.askName"
v-model:text="greeting.name"
@enter="sayHello"
autofocus
/>
</div>
<div>
<FormButton :label="dictionary.buttonReset" type="reset" @click="session.setFocus"/>
<FormButton :label="dictionary.buttonSayHello" type="button" @click="sayHello"/>
</div>
</form>
</section>
</template>
<style scoped>
...
</style>
Dynamisches Laden von JSON-Dateien (v05a)
Aufgabe: Konfiguriere und internationalisiere die Anwendung mit Hilfe von dynamischen JSON-Dateien. Dazu wird die Version v05 erweitert:
git checkout v05 # Wechsle in den Branch v05
git checkout -b v05a # Klone v05 in einen neuen Branch v05a
Internationalisierungsdateien
Die folgenden Dateien sollen dynamisch zur Laufzeit eingelesen werden. Beachten Sie, dass sie in den Ordner "public/json" verschoben werden.
// public/json/i18n_de.json
{ "phrases":
{ "hello": "Hallo, $1!"
},
"dictionary":
{ "stranger": "Fremder",
"askName": "Wie heißen Sie?",
"welcome": "Willkommen zu Web-Programmierung!",
"buttonReset": "Reset",
"buttonSayHello": "Begrüßung"
}
}
// public/json/i18n_en.json
{ "phrases":
{ "hello": "Hello, $1!"
},
"dictionary":
{ "stranger": "Stranger",
"askName": "What's your name?",
"welcome": "Welcome to Web Programing!",
"buttonReset": "reset",
"buttonSayHello": "say hello"
}
}
Er können jederzeit I18n-Dateien für weitere Sprachen definiert werden.
getJson.js
Zunächst wird eine Service-Funktion definiert zum asynchronen Laden von JSON-Dateien.
// src/service/getJson.js
/**
* @function
* @param { string } p_url - The URL of a JSON file zo be loaded
* @return { JSON } The content of the JSON file
* @throws { Error } If the file does not exists, an error is thrown
*/
async function getJson(p_url)
{ return fetch(p_url)
.then
(response =>
{ if (response.ok)
{ return response.json() }
else
{ throw new Error(`'${response.url}' not found`) }
}
)
}
export default getJson
Globale Konfigurationsdatei
// public/json/config.json
{ "startSection": "form",
"apiRoot": "/json/i18n_$1.json",
"XapiRoot": "/api/$1",
"defaultLanguage": "de"
}
// src/main.js
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import getJson from '/service/getJson'
import App from './App.vue'
const
pinia = createPinia(),
app = createApp(App),
init = async () =>
{ const
config = await getJson('/json/config.json')
config.i18n =
await getJson(config.apiRoot.replace('$1', config.defaultLanguage))
app
.provide('config', config)
.use(pinia)
.mount('#app') // app is shown to the user
}
window.addEventListener('load', init)
In der Datei main.js
könnte man die I18n-Daten abhängig von der in der Datei /json/config.json
festgelegten Defaultsprache nachladen. Dieses muss mit einem zweiten getJson
-Befehl erfolgen, der ausgeführt wird, nachdem
config.json
vollständig geladen wurde.
Besser ist es allerdings einen allgemeineren Initialisierungsmechanismus zu etablieren, mit dem man anhängig von config.json
verschiedene Daten vom Backend lädt, um die Anwendung zu initialisieren. Das machen wir später im nächsten Schritt.
StoreSession.js
und StoreGreeting.js
Wir holen uns nun in den Stores StoreSession.js
und StoreGreeting.js
die Konfigurations-Infomationen aus dem von der Main initialisierten Config-Onjekt.
Auf dieses können wir mit Hilde der Vue-Funktion inject
zugreifen.
Der Iport-Befehl zum Laden der Konfigurationsdatei muss jeweils gelöscht werden.
// src/store/StoreSession.js
...
import { ref, reactive, inject } from 'vue'
...
{ const
config = inject('config'), // contains the app configuration object
...
...
In der Datei StoreGreeting.js
müssen wir noch
config.i18n.phrases
und config.dictionary
durch
config.i18n.phrases
und config.dictionary
ersetzen.
Verallgemeinerung des Initialisierungsprozesses (v05b)
Aufgabe: Der Initialisierungsprozess soll so verallgemeinert werden, dass jedes Modul (i. Allg. verschiedene Stores) eine Initialisierungsfunktion definieren kann, die zum Zeitpunkt des App-Starts ausgeführt wird.
Als erste Anwendung erstellen wir dann einen Store StoreI18N
der die Internationalisierungsdaten per JSON lädt.
Dazu wird die Version v05b erweitert:
git checkout v05a # Wechsle in den Branch v05a
git checkout -b v05b # Klone v05a in einen neuen Branch v05b
StoreSession.js
Der Initialisierungsprozess wird vom Session-Store verwaltet. Er stellt zu diesem Zweck drei Funktionen zur Verfügung:
isInitialized
: Reaktive Variable, dietrue
enthält, sobald der Initialisierungsprozess abgeschlossen wurde.addInitializer
: Fügt eine Initialisierungsfunktion hinzu, die durch den Initialisierungsprozess ausgeführt werden soll.initialize
: Startet den Initialisierungsprozess und setztisInitialized
zum Schluss auftrue
.
Die Konstante initializers
enthält alle Initialisierungsfunktionen, die vor Start der Anwendung ausgeführt werden sollen.
Diese werden von anderen Stores mit Hilfe der Funktion addInitializer
hinzugefügt. Die Datei App.vue
aktiviert die entsprechenden Stores und führt danach die Funktion initialize
aus. Mit Hilfe des reaktiven Konstante isInitialized
erfährt die App.vue
-Komponente, wann alle Stores initialisiert sind und kann dann vom Lade-Bildschirm auf den eigentlichen Startbildschirm umschalten.
// src/store/StoreSession.js
import { defineStore } from 'pinia'
import { ref, reactive, inject } from 'vue'
const storeSession =
defineStore
( 'session', // must be unique
() =>
{ const
...
initializers = [],
isInitialized = ref(false),
addInitializer = p_initializer =>
initializers.push(new Promise(resolve => p_initializer(resolve))),
initialize = () => Promise.all(initializers)
.then(() => isInitialized.value = true)
return { initAutofocus, section, setFocus, addInitializer, initialize, isInitialized }
}
)
export default storeSession
Und nun kann man das Ganze mal ausprobieren. Solange der Ladevorgang dauert, wird ein Ladescreen angezeigt. Hier wird der Ladevorgang durch einen Zwei-Sekunde-Timer simuliert.
<!-- src/App.vue -->
<script setup>
import HelloWorld from '/component/HelloWorld.vue'
import storeSession from '/store/StoreSession'
const session = storeSession()
// fake initializer, in order to see the loading information for at least two seconds
session.addInitializer(p_resolve => setTimeout(p_resolve, 2000));
session.initialize();
</script>
<template>
<p v-if="!session.isInitialized">Loading ...</p>
<HelloWorld v-if="session.isInitialized"/>
</template>
...
StoreI18n.js
StoreI18n.js
übernimmt die I18n-Funktionalität von StoreGreeting.js
.
Damit ist die Internationalisierung in einem anwendungsunabhängigen Modul verfügbar.
Das erhöht die Wiederverwendbarkeit dieses Stores.
Ergänzt wurden:
getI18n
: eine Funktion zum Laden der I18n-Daten von einem BackendsystemchangeLang
: eine Funktion zum asynchronen Ändern der Sprache.initialize
: eine Funktion zum Initialisieren des Stores.
Die Funktion initialize
lädt die I18n-Daten für die in der Config-Datei festgelegte
Defaultsprache. Diese Funktion wird im Session-Store als Initialisierungsfunktion registriert.
// src/store/StoreI18n.js
import { defineStore } from 'pinia'
import { ref, reactive, inject } from 'vue'
import getJson from '/service/getJson'
import storeSession from '/store/StoreSession'
const
storeI18n =
defineStore
( 'i18n',
() =>
{ const
config =
inject('config'),
session =
storeSession(),
lang =
ref(null),
phrases /* Record<string, string> */ =
reactive({}),
dictionary /* Record<string, string> */=
reactive({}),
getI18n =
async p_lang =>
{ const
c_i18n_json =
await getJson(config.apiRoot.replace('$1', p_lang ?? lang.value))
Object.assign(phrases, c_i18n_json.phrases);
Object.assign(dictionary, c_i18n_json.dictionary);
},
changeLang =
async (p_lang = null) =>
{ lang.value = p_lang ?? config.defaultLanguage;
await getI18n(lang.value);
document.getElementsByTagName('html')[0].lang = lang.value;
},
initialize =
async resolve =>
{ await changeLang(config.defaultLanguage);
resolve();
}
session.addInitializer(initialize);
return { lang, phrases, dictionary, changeLang }
}
)
export default storeI18n
changeLang
enthält einen kleinen Hack, um die korrekte Sprache in das HTML-Tag der Datei "index.html" einzufügen.
document.getElementsByTagName('html')[0].lang = lang
Damit wird im Document Tree der Datei "index.html" jeweils die aktuelle Sprache verwendet:
<html lang="de">
<html lang="en">
Man beachte, dass im Skript-Bereich des Moduls App.vue
der Store mittels storeI18n()
erstmals aufgerufen muss, damit er initialisiert wird. Insbesondere wird dabei der Befehl session.addInitializer(initialize)
ausgeführt, das heißt die Initialisierungsfunktion zum Session-Store hinzugefügt.
Fügen Sie also den den Aufruf storeI18n()
samt zugehörigem Import-Befehl in die
Datei App.vue
ein. (Den Fake-Initializer können Sie deaktivieren, wenn Sie wollen. Er wird nicht mehr benötigt.)
main.js
Die Konfiguration in der Datei main.js
kann nun vereinfacht werden.
// src/main.js
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import getJson from '/service/getJson'
import App from './App.vue'
const
pinia = createPinia(),
app = createApp(App),
init = async () =>
{ app
.provide('config', await getJson('/json/config.json'))
.use(pinia)
.mount('#app') // app is shown to the user
}
window.addEventListener('load', init)
StoreGreeting.js
Der Inhalt von StoreGreeting.js
vereinfacht sich entsprechend.
Diese Datei nur noch Funktionen zur Verfügung, der in der Phrase phrases.hello
den String $1
durch einen Namen ersetzt.
// src/store/StoreGreeting.js
import { defineStore } from 'pinia'
import { ref, computed, readonly } from 'vue'
import StoreI18n from './StoreI18n'
const storeGreeting =
defineStore
( 'greeting',
() =>
{ const
i18n =
StoreI18n(),
phrases =
i18n.phrases,
dictionary =
i18n.dictionary,
f_hello =
p_name => phrases.hello.replace('$1', p_name === '' ? dictionary.stranger : p_name),
...
Benutzung eines Backend-Servers (v05c)
Aufgabe: Die I18N-Daten sollen von einem Backend-Server gelesen werden.
Dazu wird die Version v05b erweitert:
git checkout v05b
git checkout -b v05c
Als ersten Backend-Server verwenden wir den JSON-Server, einen Fake-REST-Server.
npm i -D json-server
Um ihn mittels "npm run server" zu starten, wird folgendes Skript in die Datei package.json eingefügt.
"server": "npx json-server --watch db.json --port 4000"
JSON-Server-Daten
// db.json
{ "v1":
[ { "id": "de",
"phrases":
{ "hello": "Hallo, $1!"
},
"dictionary":
{ "stranger": "Fremdling",
"askName": "Wie heißen Sie?",
"welcome": "Willkommen zu Web-Programmierung!",
"buttonReset": "Reset",
"buttonSayHello": "Begrüßung"
}
},
{ "id": "en",
"phrases":
{ "hello": "Hello, $1!"
},
"dictionary":
{ "stranger": "Stranger",
"askName": "What's your name?",
"welcome": "Welcome to Web Programing!",
"buttonReset": "reset",
"buttonSayHello": "say hello"
}
}
]
}
Testen Sie dann Ihren JSON-Server, indem Sie ihn starten und dann in der Datei test.rest
auf die jeweiligen Send-Request-Anweisungen klicken:
npm run server
// test.rest
###
GET http://localhost:4000/ HTTP/1.1
###
GET http://localhost:4000/v1/ HTTP/1.1
###
GET http://localhost:4000/v1/de HTTP/1.1
###
GET http://localhost:4000/v1/en HTTP/1.1
Vue-Server als Proxy
// vite.config.common.js
...
export default defineConfig
({...
resolve:
{ ...
},
server:
{ proxy:
{ '/api':
{ target: 'http://localhost:4000/',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '/v1')
}
}
},
})
Starten Sie nun beide Server und testen Sie die Hello-World-Anwendung Browser:
npm run server # 1. Terminal
npm run dev # 2. Terminal
http://localhost:5173/api
http://localhost:5173/api/de
http://localhost:5173/api/en
http://localhost:4000/v1
http://localhost:4000/v1/de
http://localhost:4000/v1/en
Die Vue-URLs funktionieren im Browser, aber im Gegensatz zu den JSON-Server-URLs nicht in test.rest
, da Vue keine echte REST-API zur Verfügung stellt.
Zugriff auf den REST-Server
Um auf den neuen REST-Server zuzugreifen, reicht es,
die URL in der Datei config.json
anzupassen:
// public/json/config.json
{ "startSection": "form",
"XapiRoot": "/json/i18n_$1.json",
"apiRoot": "/api/$1",
"defaultLanguage": "de"
}
Die Dateien public/json/i18n_de.json
und public/json/i18n_en.json
werden nicht mehr benötigt.
wk_express_hello_world (v00)
mkdir express_hello_world
cd express_hello_world
npm init -y
npm i express dotenv
npm i -D nodemon
# Dateien erstellen/bearbeiten
npm run server
package.json
// package.json
...
"scripts": {
"server": "nodemon -r dotenv/config src/server.js",
"prod": "node -r dotenv/config src/server.js"
},
"type": "module",
...
src/index.html
<!-- src/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width,
initial-scale=1,
shrink-to-fit=no"
>
<title>Express Hello World 01</title>
</head>
<body>
<section>
<h1>Hello, World!</h1>
</section>
</body>
</html>
src/server.js
// src/server.js
import express from 'express'
import path from 'path'
const
{ PORT = 4000,
SERVER = `http://localhost:${PORT}`
} = process.env,
c_app = express(),
c_dirname = path.resolve(path.dirname(process.argv[1]))
c_app.get
('/',
(req, res) =>
{ //console.log(c_dirname);
res.sendFile('./index.html', {root: c_dirname});
}
);
c_app.listen(PORT);
console.log(`Running on ${SERVER}`);
wk_express_hello_world (v01)
Kopieren Sie das Array aus der Datei db.json
der Version v05a
in die Datei src/db.json
und ersetzen Sie in dieser Datei zweimal "id"
durch "lang
. Den Inhalt dieser Datei geben wir nun mit Hilfe eines Express-Servers aus.
src/server.js
import express, { response } from 'express'
import path from 'path'
let db;
const
{ PORT = 4000,
SERVER = `http://localhost:${PORT}`,
DB = `${SERVER}/db.json`
} = process.env ,
c_app = express(),
c_dirname = path.resolve(path.dirname(process.argv[1]))
;
c_app
.get
( '/',
(req, res) =>
{ res.sendFile('./index.html', {root: c_dirname }); }
)
.get
( '/db.json',
(req, res) =>
{ res.sendFile('./db.json', {root: c_dirname }); }
)
.get
( '/v1/:lang',
(req, res) =>
{ //console.log(req.params.lang);
const l_i18n = db.filter(i18n => i18n.lang === req.params.lang)[0];
res.json(l_i18n);
}
)
.get
( '/v1/:lang/:type',
(req, res) =>
{ //console.log(req.params.lang, req.params.type);
const l_i18n = db.filter(i18n => i18n.lang === req.params.lang)[0];
res.json(l_i18n[req.params.type]);
}
);
async function init()
{ c_app.listen(PORT);
db = await fetch(DB).then(response => response.json())
console.log(`Server is running on ${SERVER}`)
}
init()
Benutzung von Strapi als Backend-Servers (v05c)
Erstellen Sie eine Strap-Datenbank gemäß den Vorgaben aus der Vorlesung (Miro).
Um darauf zuzugreifen, müssen Sie drei Dateien anpassen:
Konfiguration
// /public/json/config.json: Api-Root
{ "startSection": "form",
"XapiRoot": "/json/i18n_$1.json",
"apiRoot": "/api/$1",
"defaultLanguage": "de"
}
Proxy
// /vite.config.js: Port 1337 und Rewrite-Regel
...
server:
{ proxy:
{ '/api':
{ target: 'http://localhost:1337/',
changeOrigin: true,
rewrite: path => path.replace(/^\/api\//, '/api/i18ns?filters[lang][$eq]=')
}
}
},
Datenextraktion
...
getI18n =
async p_lang =>
{ const
c_api_data =
await getJson(config.apiRoot.replace('$1', p_lang ?? lang.value))
c_i18n_json =
c_api_data.data[0].attributes;
Object.assign(phrases, c_i18n_json.phrases);
Object.assign(dictionary, c_i18n_json.dictionary);
},
...
Fortsetzung des Tutoriums
Sie sollten nun Teil 6 des Vue-Tutoriums bearbeiten. In diesem Tutorium setzen Sie Routing ein, auch wenn das für die Hello-World-Anwendung nicht sonderlich sinnvoll ist.
Quellen
- Kowarschick (WebProg): Wolfgang Kowarschick; Vorlesung „Web-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2024; Quellengüte: 3 (Vorlesung)