Update TypeScript configuration for stricter type checks and modify environment variable access. Exclude additional directories from compilation, enhance error handling in resolvers, and improve random element selection in mock data generation. Refactor locale handling in middleware and update GraphQL client to use bracket notation for environment variables.
This commit is contained in:
@@ -36,7 +36,12 @@ const descriptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
function getRandomElement<T>(array: T[]): T {
|
function getRandomElement<T>(array: T[]): T {
|
||||||
return array[Math.floor(Math.random() * array.length)];
|
const index = Math.floor(Math.random() * array.length);
|
||||||
|
const element = array[index];
|
||||||
|
if (element === undefined) {
|
||||||
|
throw new Error("Array is empty");
|
||||||
|
}
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandomPrice(): number {
|
function getRandomPrice(): number {
|
||||||
@@ -57,9 +62,14 @@ function generateProduct(id: string): Product {
|
|||||||
const promotionType = Math.random();
|
const promotionType = Math.random();
|
||||||
if (promotionType < 0.33) {
|
if (promotionType < 0.33) {
|
||||||
// Sale mit Rabatt
|
// Sale mit Rabatt
|
||||||
const discountPercent = [10, 20, 30, 40, 50][
|
const discountPercentArray = [10, 20, 30, 40, 50];
|
||||||
Math.floor(Math.random() * 5)
|
const discountPercent =
|
||||||
|
discountPercentArray[
|
||||||
|
Math.floor(Math.random() * discountPercentArray.length)
|
||||||
];
|
];
|
||||||
|
if (discountPercent === undefined) {
|
||||||
|
throw new Error("Discount percent array is empty");
|
||||||
|
}
|
||||||
originalPrice = basePrice;
|
originalPrice = basePrice;
|
||||||
price = Math.round(basePrice * (1 - discountPercent / 100) * 100) / 100;
|
price = Math.round(basePrice * (1 - discountPercent / 100) * 100) / 100;
|
||||||
promotion = {
|
promotion = {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { DataAdapter } from "./interface";
|
|||||||
* Bestimmt welcher Adapter basierend auf Environment-Variablen verwendet wird
|
* Bestimmt welcher Adapter basierend auf Environment-Variablen verwendet wird
|
||||||
*/
|
*/
|
||||||
export function createAdapter(): DataAdapter {
|
export function createAdapter(): DataAdapter {
|
||||||
const adapterType = process.env.DATA_ADAPTER || "mock";
|
const adapterType = process.env["DATA_ADAPTER"] || "mock";
|
||||||
|
|
||||||
switch (adapterType) {
|
switch (adapterType) {
|
||||||
case "mock":
|
case "mock":
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import jwt from "jsonwebtoken";
|
import jwt, { type SignOptions } from "jsonwebtoken";
|
||||||
import type { JWTPayload, UserRole } from "../types/user.js";
|
import type { JWTPayload } from "../types/user.js";
|
||||||
|
import { UserRole } from "../types/user.js";
|
||||||
import { logger } from "../monitoring/logger.js";
|
import { logger } from "../monitoring/logger.js";
|
||||||
|
|
||||||
const JWT_SECRET =
|
const JWT_SECRET: string =
|
||||||
process.env.JWT_SECRET || "your-secret-key-change-in-production";
|
process.env["JWT_SECRET"] || "your-secret-key-change-in-production";
|
||||||
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || "7d";
|
const JWT_EXPIRES_IN: string = process.env["JWT_EXPIRES_IN"] || "7d";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erstellt ein JWT Token für einen User
|
* Erstellt ein JWT Token für einen User
|
||||||
@@ -12,7 +13,7 @@ const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || "7d";
|
|||||||
export function createToken(payload: JWTPayload): string {
|
export function createToken(payload: JWTPayload): string {
|
||||||
return jwt.sign(payload, JWT_SECRET, {
|
return jwt.sign(payload, JWT_SECRET, {
|
||||||
expiresIn: JWT_EXPIRES_IN,
|
expiresIn: JWT_EXPIRES_IN,
|
||||||
});
|
} as SignOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +43,7 @@ export function extractTokenFromHeader(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parts[1];
|
return parts[1] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import type {
|
import type { User, LoginCredentials, RegisterData } from "../types/user.js";
|
||||||
User,
|
import { UserRole } from "../types/user.js";
|
||||||
UserRole,
|
|
||||||
LoginCredentials,
|
|
||||||
RegisterData,
|
|
||||||
} from "../types/user.js";
|
|
||||||
import { hashPassword, comparePassword } from "./password.js";
|
import { hashPassword, comparePassword } from "./password.js";
|
||||||
import { createToken, verifyToken } from "./jwt.js";
|
import { createToken, verifyToken } from "./jwt.js";
|
||||||
import { logger } from "../monitoring/logger.js";
|
import { logger } from "../monitoring/logger.js";
|
||||||
@@ -22,7 +18,7 @@ export class UserService {
|
|||||||
*/
|
*/
|
||||||
async register(
|
async register(
|
||||||
data: RegisterData,
|
data: RegisterData,
|
||||||
role: UserRole = "customer"
|
role: UserRole = UserRole.CUSTOMER
|
||||||
): Promise<{
|
): Promise<{
|
||||||
user: User;
|
user: User;
|
||||||
token: string;
|
token: string;
|
||||||
|
|||||||
@@ -4,16 +4,15 @@
|
|||||||
*/
|
*/
|
||||||
export const cacheConfig = {
|
export const cacheConfig = {
|
||||||
pages: {
|
pages: {
|
||||||
ttl: parseInt(process.env.CACHE_PAGES_TTL || '60000'), // 60 Sekunden
|
ttl: parseInt(process.env["CACHE_PAGES_TTL"] || "60000"), // 60 Sekunden
|
||||||
},
|
},
|
||||||
pageSeo: {
|
pageSeo: {
|
||||||
ttl: parseInt(process.env.CACHE_PAGE_SEO_TTL || '300000'), // 5 Minuten
|
ttl: parseInt(process.env["CACHE_PAGE_SEO_TTL"] || "300000"), // 5 Minuten
|
||||||
},
|
},
|
||||||
navigation: {
|
navigation: {
|
||||||
ttl: parseInt(process.env.CACHE_NAVIGATION_TTL || '300000'), // 5 Minuten
|
ttl: parseInt(process.env["CACHE_NAVIGATION_TTL"] || "300000"), // 5 Minuten
|
||||||
},
|
},
|
||||||
products: {
|
products: {
|
||||||
ttl: parseInt(process.env.CACHE_PRODUCTS_TTL || '30000'), // 30 Sekunden
|
ttl: parseInt(process.env["CACHE_PRODUCTS_TTL"] || "30000"), // 30 Sekunden
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type { DataAdapter } from "./adapters/interface.js";
|
|||||||
import { createAdapter } from "./adapters/config.js";
|
import { createAdapter } from "./adapters/config.js";
|
||||||
import type { PageSeo, Page, Navigation, Product } from "./types/index.js";
|
import type { PageSeo, Page, Navigation, Product } from "./types/index.js";
|
||||||
import type { TranslationsData } from "./adapters/Mock/_i18n/mockTranslations.js";
|
import type { TranslationsData } from "./adapters/Mock/_i18n/mockTranslations.js";
|
||||||
import { AdapterError } from "./utils/errors.js";
|
|
||||||
import { cache } from "./utils/cache.js";
|
import { cache } from "./utils/cache.js";
|
||||||
import { CacheKeyBuilder } from "./utils/cacheKeys.js";
|
import { CacheKeyBuilder } from "./utils/cacheKeys.js";
|
||||||
import { DataServiceHelpers } from "./utils/dataServiceHelpers.js";
|
import { DataServiceHelpers } from "./utils/dataServiceHelpers.js";
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ import { getMetrics } from "./monitoring/metrics.js";
|
|||||||
import { extractTokenFromHeader } from "./auth/jwt.js";
|
import { extractTokenFromHeader } from "./auth/jwt.js";
|
||||||
import { userService } from "./auth/userService.js";
|
import { userService } from "./auth/userService.js";
|
||||||
|
|
||||||
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 4000;
|
const PORT = process.env["PORT"] ? parseInt(process.env["PORT"]) : 4000;
|
||||||
const METRICS_PORT = process.env.METRICS_PORT
|
const METRICS_PORT = process.env["METRICS_PORT"]
|
||||||
? parseInt(process.env.METRICS_PORT)
|
? parseInt(process.env["METRICS_PORT"])
|
||||||
: 9090;
|
: 9090;
|
||||||
|
|
||||||
// Konfiguration aus Environment Variables
|
// Konfiguration aus Environment Variables
|
||||||
const MAX_QUERY_COMPLEXITY = process.env.MAX_QUERY_COMPLEXITY
|
const MAX_QUERY_COMPLEXITY = process.env["MAX_QUERY_COMPLEXITY"]
|
||||||
? parseInt(process.env.MAX_QUERY_COMPLEXITY)
|
? parseInt(process.env["MAX_QUERY_COMPLEXITY"])
|
||||||
: 1000;
|
: 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import winston from "winston";
|
|||||||
* Erstellt JSON-Logs für bessere Analyse und Monitoring
|
* Erstellt JSON-Logs für bessere Analyse und Monitoring
|
||||||
*/
|
*/
|
||||||
export const logger = winston.createLogger({
|
export const logger = winston.createLogger({
|
||||||
level: process.env.LOG_LEVEL || "info",
|
level: process.env["LOG_LEVEL"] || "info",
|
||||||
format: winston.format.combine(
|
format: winston.format.combine(
|
||||||
winston.format.timestamp(),
|
winston.format.timestamp(),
|
||||||
winston.format.errors({ stack: true }),
|
winston.format.errors({ stack: true }),
|
||||||
@@ -13,7 +13,7 @@ export const logger = winston.createLogger({
|
|||||||
),
|
),
|
||||||
defaultMeta: {
|
defaultMeta: {
|
||||||
service: "graphql-middlelayer",
|
service: "graphql-middlelayer",
|
||||||
environment: process.env.NODE_ENV || "development",
|
environment: process.env["NODE_ENV"] || "development",
|
||||||
},
|
},
|
||||||
transports: [
|
transports: [
|
||||||
// Console Output (für Development)
|
// Console Output (für Development)
|
||||||
@@ -29,7 +29,7 @@ export const logger = winston.createLogger({
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
// File Output (für Production)
|
// File Output (für Production)
|
||||||
...(process.env.NODE_ENV === "production"
|
...(process.env["NODE_ENV"] === "production"
|
||||||
? [
|
? [
|
||||||
new winston.transports.File({
|
new winston.transports.File({
|
||||||
filename: "logs/error.log",
|
filename: "logs/error.log",
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export const resolvers = {
|
|||||||
products: async (
|
products: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { limit?: number },
|
args: { limit?: number },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(() => dataService.getProducts(args.limit));
|
return withErrorHandling(() => dataService.getProducts(args.limit));
|
||||||
},
|
},
|
||||||
@@ -71,7 +71,7 @@ export const resolvers = {
|
|||||||
pageSeo: async (
|
pageSeo: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { locale?: string },
|
args: { locale?: string },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(() => dataService.getPageSeo(args.locale));
|
return withErrorHandling(() => dataService.getPageSeo(args.locale));
|
||||||
},
|
},
|
||||||
@@ -96,14 +96,14 @@ export const resolvers = {
|
|||||||
pages: async (
|
pages: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { locale?: string },
|
args: { locale?: string },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(() => dataService.getPages(args.locale));
|
return withErrorHandling(() => dataService.getPages(args.locale));
|
||||||
},
|
},
|
||||||
homepage: async (
|
homepage: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { locale?: string },
|
args: { locale?: string },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(async () => {
|
return withErrorHandling(async () => {
|
||||||
// Homepage ist immer die Seite mit dem Slug "/"
|
// Homepage ist immer die Seite mit dem Slug "/"
|
||||||
@@ -117,7 +117,7 @@ export const resolvers = {
|
|||||||
navigation: async (
|
navigation: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { locale?: string },
|
args: { locale?: string },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(() => dataService.getNavigation(args.locale));
|
return withErrorHandling(() => dataService.getNavigation(args.locale));
|
||||||
},
|
},
|
||||||
@@ -133,7 +133,7 @@ export const resolvers = {
|
|||||||
translations: async (
|
translations: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { locale?: string; namespace?: string },
|
args: { locale?: string; namespace?: string },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(() =>
|
return withErrorHandling(() =>
|
||||||
dataService.getTranslations(args.locale, args.namespace)
|
dataService.getTranslations(args.locale, args.namespace)
|
||||||
@@ -144,7 +144,7 @@ export const resolvers = {
|
|||||||
register: async (
|
register: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { email: string; password: string; name: string },
|
args: { email: string; password: string; name: string },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(async () => {
|
return withErrorHandling(async () => {
|
||||||
const result = await userService.register({
|
const result = await userService.register({
|
||||||
@@ -167,7 +167,7 @@ export const resolvers = {
|
|||||||
login: async (
|
login: async (
|
||||||
_: unknown,
|
_: unknown,
|
||||||
args: { email: string; password: string },
|
args: { email: string; password: string },
|
||||||
context: GraphQLContext
|
_context: GraphQLContext
|
||||||
) => {
|
) => {
|
||||||
return withErrorHandling(async () => {
|
return withErrorHandling(async () => {
|
||||||
const result = await userService.login({
|
const result = await userService.login({
|
||||||
|
|||||||
@@ -9,6 +9,16 @@ import type { c_youtubeVideo } from "./c_youtubeVideo";
|
|||||||
import type { c_headline } from "./c_headline";
|
import type { c_headline } from "./c_headline";
|
||||||
|
|
||||||
export type { contentLayout };
|
export type { contentLayout };
|
||||||
|
export type {
|
||||||
|
c_html,
|
||||||
|
c_markdown,
|
||||||
|
c_iframe,
|
||||||
|
c_imageGallery,
|
||||||
|
c_image,
|
||||||
|
c_quote,
|
||||||
|
c_youtubeVideo,
|
||||||
|
c_headline,
|
||||||
|
};
|
||||||
export type ContentItem =
|
export type ContentItem =
|
||||||
| c_html
|
| c_html
|
||||||
| c_markdown
|
| c_markdown
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class InMemoryCache<T> implements CacheInterface<T> {
|
|||||||
* Cache-Instanzen
|
* Cache-Instanzen
|
||||||
* Verwendet Redis wenn aktiviert, sonst In-Memory
|
* Verwendet Redis wenn aktiviert, sonst In-Memory
|
||||||
*/
|
*/
|
||||||
const useRedis = process.env.REDIS_ENABLED === "true";
|
const useRedis = process.env["REDIS_ENABLED"] === "true";
|
||||||
|
|
||||||
export const cache = {
|
export const cache = {
|
||||||
pages: useRedis
|
pages: useRedis
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const createPageLoader = () => {
|
|||||||
keys.map((key) => {
|
keys.map((key) => {
|
||||||
// Parse Key: Format kann "slug:locale" oder "slug" sein
|
// Parse Key: Format kann "slug:locale" oder "slug" sein
|
||||||
const parts = key.split(":");
|
const parts = key.split(":");
|
||||||
const slug = parts[0];
|
const slug = parts[0] ?? "";
|
||||||
const locale = parts.length > 1 ? parts[1] : undefined;
|
const locale = parts.length > 1 ? parts[1] : undefined;
|
||||||
return dataService.getPage(slug, locale);
|
return dataService.getPage(slug, locale);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export class RedisCache<T> {
|
|||||||
constructor(defaultTTL: number, cacheType: string) {
|
constructor(defaultTTL: number, cacheType: string) {
|
||||||
this.defaultTTL = defaultTTL;
|
this.defaultTTL = defaultTTL;
|
||||||
this.cacheType = cacheType;
|
this.cacheType = cacheType;
|
||||||
this.useRedis = process.env.REDIS_ENABLED === "true";
|
this.useRedis = process.env["REDIS_ENABLED"] === "true";
|
||||||
|
|
||||||
if (this.useRedis) {
|
if (this.useRedis) {
|
||||||
this.initRedis();
|
this.initRedis();
|
||||||
@@ -30,9 +30,9 @@ export class RedisCache<T> {
|
|||||||
private async initRedis() {
|
private async initRedis() {
|
||||||
try {
|
try {
|
||||||
this.redis = new Redis({
|
this.redis = new Redis({
|
||||||
host: process.env.REDIS_HOST || "localhost",
|
host: process.env["REDIS_HOST"] || "localhost",
|
||||||
port: parseInt(process.env.REDIS_PORT || "6379"),
|
port: parseInt(process.env["REDIS_PORT"] || "6379"),
|
||||||
password: process.env.REDIS_PASSWORD,
|
password: process.env["REDIS_PASSWORD"],
|
||||||
retryStrategy: (times) => {
|
retryStrategy: (times) => {
|
||||||
// Bei Fehler: Fallback auf In-Memory nach 3 Versuchen
|
// Bei Fehler: Fallback auf In-Memory nach 3 Versuchen
|
||||||
if (times > 3) {
|
if (times > 3) {
|
||||||
|
|||||||
@@ -86,8 +86,9 @@ export default function LoginModal() {
|
|||||||
|
|
||||||
const result: GraphQLResponse<LoginResponse> = await response.json();
|
const result: GraphQLResponse<LoginResponse> = await response.json();
|
||||||
|
|
||||||
if (result.errors) {
|
if (result.errors && result.errors.length > 0) {
|
||||||
setError(result.errors[0].message || t("login.error"));
|
const firstError = result.errors[0];
|
||||||
|
setError(firstError?.message || t("login.error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +127,9 @@ export default function LoginModal() {
|
|||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between items-center mb-6">
|
<div className="flex justify-between items-center mb-6">
|
||||||
<h2 className="text-2xl font-bold text-gray-900">{t("login.title")}</h2>
|
<h2 className="text-2xl font-bold text-gray-900">
|
||||||
|
{t("login.title")}
|
||||||
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={close}
|
onClick={close}
|
||||||
className="text-gray-400 hover:text-gray-600 transition-colors"
|
className="text-gray-400 hover:text-gray-600 transition-colors"
|
||||||
@@ -217,4 +220,3 @@ export default function LoginModal() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,8 +105,9 @@ export default function RegisterModal() {
|
|||||||
|
|
||||||
const result: GraphQLResponse<RegisterResponse> = await response.json();
|
const result: GraphQLResponse<RegisterResponse> = await response.json();
|
||||||
|
|
||||||
if (result.errors) {
|
if (result.errors && result.errors.length > 0) {
|
||||||
setError(result.errors[0].message || t("register.error"));
|
const firstError = result.errors[0];
|
||||||
|
setError(firstError?.message || t("register.error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,8 +114,9 @@ export function loginModalData(): any {
|
|||||||
|
|
||||||
const result: GraphQLResponse<LoginResponse> = await response.json();
|
const result: GraphQLResponse<LoginResponse> = await response.json();
|
||||||
|
|
||||||
if (result.errors) {
|
if (result.errors && result.errors.length > 0) {
|
||||||
this.error = result.errors[0].message;
|
const firstError = result.errors[0];
|
||||||
|
this.error = firstError?.message || "An error occurred";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,8 +133,9 @@ export function registerModalData(): any {
|
|||||||
|
|
||||||
const result: GraphQLResponse<RegisterResponse> = await response.json();
|
const result: GraphQLResponse<RegisterResponse> = await response.json();
|
||||||
|
|
||||||
if (result.errors) {
|
if (result.errors && result.errors.length > 0) {
|
||||||
this.error = result.errors[0].message;
|
const firstError = result.errors[0];
|
||||||
|
this.error = firstError?.message || "An error occurred";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getToken } from "../auth/authService.js";
|
import { getToken } from "../auth/authService.js";
|
||||||
|
|
||||||
const GRAPHQL_URL =
|
const GRAPHQL_URL =
|
||||||
import.meta.env.PUBLIC_GRAPHQL_URL || "http://localhost:4000";
|
import.meta.env["PUBLIC_GRAPHQL_URL"] || "http://localhost:4000";
|
||||||
|
|
||||||
interface GraphQLResponse<T> {
|
interface GraphQLResponse<T> {
|
||||||
data?: T;
|
data?: T;
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ class I18n {
|
|||||||
private loadDefaults(): void {
|
private loadDefaults(): void {
|
||||||
const defaults =
|
const defaults =
|
||||||
defaultTranslations[this.locale] || defaultTranslations["de"];
|
defaultTranslations[this.locale] || defaultTranslations["de"];
|
||||||
|
if (defaults) {
|
||||||
Object.entries(defaults).forEach(([key, value]) => {
|
Object.entries(defaults).forEach(([key, value]) => {
|
||||||
this.translations.set(key, value);
|
this.translations.set(key, value);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// Markiere als geladen, damit Defaults sofort verfügbar sind
|
// Markiere als geladen, damit Defaults sofort verfügbar sind
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
}
|
}
|
||||||
@@ -83,7 +85,7 @@ class I18n {
|
|||||||
|
|
||||||
// Füge namespace nur hinzu, wenn es definiert ist
|
// Füge namespace nur hinzu, wenn es definiert ist
|
||||||
if (namespace) {
|
if (namespace) {
|
||||||
variables.namespace = namespace;
|
variables["namespace"] = namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = namespace
|
const query = namespace
|
||||||
@@ -150,7 +152,7 @@ class I18n {
|
|||||||
if (!translation) {
|
if (!translation) {
|
||||||
const defaults =
|
const defaults =
|
||||||
defaultTranslations[this.locale] || defaultTranslations["de"];
|
defaultTranslations[this.locale] || defaultTranslations["de"];
|
||||||
translation = defaults[key] || key;
|
translation = defaults?.[key] || key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ersetze Platzhalter {param}
|
// Ersetze Platzhalter {param}
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ export const onRequest = defineMiddleware((context, next) => {
|
|||||||
context.locals.pathWithoutLocale = pathWithoutLocale;
|
context.locals.pathWithoutLocale = pathWithoutLocale;
|
||||||
|
|
||||||
// Setze Locale in Cookie für persistente Auswahl
|
// Setze Locale in Cookie für persistente Auswahl
|
||||||
|
if (locale) {
|
||||||
context.cookies.set("locale", locale, {
|
context.cookies.set("locale", locale, {
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 60 * 60 * 24 * 365, // 1 Jahr
|
maxAge: 60 * 60 * 24 * 365, // 1 Jahr
|
||||||
sameSite: "lax",
|
sameSite: "lax",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Keine Locale in URL: Browser-Locale oder Cookie verwenden
|
// Keine Locale in URL: Browser-Locale oder Cookie verwenden
|
||||||
const cookieLocale = context.cookies.get("locale")?.value;
|
const cookieLocale = context.cookies.get("locale")?.value;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { i18n } from "../../lib/i18n/i18n.js";
|
|||||||
import PageContent from "../../components/PageContent.astro";
|
import PageContent from "../../components/PageContent.astro";
|
||||||
import type { Page } from "../../lib/types/page.js";
|
import type { Page } from "../../lib/types/page.js";
|
||||||
|
|
||||||
const locale = Astro.params.locale || "de";
|
const locale = Astro.params["locale"] || "de";
|
||||||
i18n.setLocale(locale);
|
i18n.setLocale(locale);
|
||||||
|
|
||||||
let page: Page | null = await loadPage("/404", locale, "404-Seite");
|
let page: Page | null = await loadPage("/404", locale, "404-Seite");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { i18n } from "../../lib/i18n/i18n.js";
|
|||||||
import PageContent from "../../components/PageContent.astro";
|
import PageContent from "../../components/PageContent.astro";
|
||||||
import type { Page } from "../../lib/types/page.js";
|
import type { Page } from "../../lib/types/page.js";
|
||||||
|
|
||||||
const locale = Astro.params.locale || "de";
|
const locale = Astro.params["locale"] || "de";
|
||||||
i18n.setLocale(locale);
|
i18n.setLocale(locale);
|
||||||
|
|
||||||
let page: Page | null = await loadPage("/500", locale, "500-Seite");
|
let page: Page | null = await loadPage("/500", locale, "500-Seite");
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import { getPage, getHomepage } from "../../lib/graphql/cmsQueries.js";
|
|||||||
import { i18n } from "../../lib/i18n/i18n.js";
|
import { i18n } from "../../lib/i18n/i18n.js";
|
||||||
import ContentRow from "../../components/ContentRow.astro";
|
import ContentRow from "../../components/ContentRow.astro";
|
||||||
|
|
||||||
const locale = Astro.params.locale || "de";
|
const locale = Astro.params["locale"] || "de";
|
||||||
// Bei [...slug] kommt slug als String (z.B. "about" für /de/about)
|
// Bei [...slug] kommt slug als String (z.B. "about" für /de/about)
|
||||||
// Konvertiere zu String mit führendem Slash
|
// Konvertiere zu String mit führendem Slash
|
||||||
const slugParam = Astro.params.slug;
|
const slugParam = Astro.params["slug"];
|
||||||
const slug = slugParam ? `/${slugParam}` : "/";
|
const slug = slugParam ? `/${slugParam}` : "/";
|
||||||
|
|
||||||
// Setze Locale im i18n-System
|
// Setze Locale im i18n-System
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { i18n } from "../../lib/i18n/i18n.js";
|
|||||||
import PageContent from "../../components/PageContent.astro";
|
import PageContent from "../../components/PageContent.astro";
|
||||||
import type { Page } from "../../lib/types/page.js";
|
import type { Page } from "../../lib/types/page.js";
|
||||||
|
|
||||||
const locale = Astro.params.locale || "de";
|
const locale = Astro.params["locale"] || "de";
|
||||||
i18n.setLocale(locale);
|
i18n.setLocale(locale);
|
||||||
|
|
||||||
let page: Page | null = await loadPage("/", locale, "Homepage");
|
let page: Page | null = await loadPage("/", locale, "Homepage");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { getProducts } from "../../../lib/graphql/queries.js";
|
|||||||
import { i18n } from "../../../lib/i18n/i18n.js";
|
import { i18n } from "../../../lib/i18n/i18n.js";
|
||||||
import type { Product as ProductType } from "../../../lib/types/product.js";
|
import type { Product as ProductType } from "../../../lib/types/product.js";
|
||||||
|
|
||||||
const locale = Astro.params.locale || "de";
|
const locale = Astro.params["locale"] || "de";
|
||||||
i18n.setLocale(locale);
|
i18n.setLocale(locale);
|
||||||
|
|
||||||
let products: ProductType[] = [];
|
let products: ProductType[] = [];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "astro/tsconfigs/strict",
|
"extends": "astro/tsconfigs/strict",
|
||||||
"include": [".astro/types.d.ts", "**/*"],
|
"include": [".astro/types.d.ts", "**/*"],
|
||||||
"exclude": ["dist"],
|
"exclude": ["dist", "middlelayer/__cms/**/*"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
@@ -10,6 +10,21 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@middlelayer-types/*": ["middlelayer/types/*"],
|
"@middlelayer-types/*": ["middlelayer/types/*"],
|
||||||
"@middlelayer/*": ["middlelayer/*"]
|
"@middlelayer/*": ["middlelayer/*"]
|
||||||
}
|
},
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictBindCallApply": true,
|
||||||
|
"strictPropertyInitialization": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user