Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac0bb02ba0 | ||
|
|
63269c2600 | ||
|
|
17a39d677d |
@@ -38,6 +38,9 @@ RUN if [ -n "$APP_VERSION" ]; then \
|
|||||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||||
ENV NEXT_TELEMETRY_DISABLED 1
|
ENV NEXT_TELEMETRY_DISABLED 1
|
||||||
|
|
||||||
|
# Suppress baseline-browser-mapping warning about old data (informational only)
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
# Generate Prisma Client
|
# Generate Prisma Client
|
||||||
ENV DATABASE_URL="file:./dev.db"
|
ENV DATABASE_URL="file:./dev.db"
|
||||||
RUN node_modules/.bin/prisma generate
|
RUN node_modules/.bin/prisma generate
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Hördle unterstützt vollständige Mehrsprachigkeit für Deutsch und Englisch.
|
|||||||
**Schnellstart:**
|
**Schnellstart:**
|
||||||
- Deutsche Version: `http://localhost:3000/de`
|
- Deutsche Version: `http://localhost:3000/de`
|
||||||
- Englische Version: `http://localhost:3000/en`
|
- Englische Version: `http://localhost:3000/en`
|
||||||
- Root (`/`) leitet automatisch zur Standardsprache (Deutsch) um
|
- Root (`/`) leitet automatisch zur Standardsprache (Englisch) um
|
||||||
|
|
||||||
## White Labeling
|
## White Labeling
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ Das Ziel ist es, den Song mit so wenigen Hinweisen wie möglich zu erraten und d
|
|||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
Die App läuft unter `http://localhost:3000` (leitet automatisch zu `/de` um).
|
Die App läuft unter `http://localhost:3000` (leitet automatisch zu `/en` um).
|
||||||
|
|
||||||
## Deployment mit Docker
|
## Deployment mit Docker
|
||||||
|
|
||||||
|
|||||||
@@ -275,8 +275,8 @@ export default function Game({ dailyPuzzle, genre = null, isSpecial = false, max
|
|||||||
const genreText = genre ? `${isSpecial ? t('special') : t('genre')}: ${genre}\n` : '';
|
const genreText = genre ? `${isSpecial ? t('special') : t('genre')}: ${genre}\n` : '';
|
||||||
|
|
||||||
let shareUrl = `https://${config.domain}`;
|
let shareUrl = `https://${config.domain}`;
|
||||||
// Add locale prefix if not default (de)
|
// Add locale prefix if not default (en)
|
||||||
if (locale !== 'de') {
|
if (locale !== 'en') {
|
||||||
shareUrl += `/${locale}`;
|
shareUrl += `/${locale}`;
|
||||||
}
|
}
|
||||||
if (genre) {
|
if (genre) {
|
||||||
|
|||||||
14
docs/I18N.md
14
docs/I18N.md
@@ -8,14 +8,14 @@ Die i18n-Implementierung basiert auf [next-intl](https://next-intl-docs.vercel.a
|
|||||||
|
|
||||||
## Unterstützte Sprachen
|
## Unterstützte Sprachen
|
||||||
|
|
||||||
- **Deutsch (de)** - Standardsprache
|
- **Englisch (en)** - Standardsprache
|
||||||
- **Englisch (en)**
|
- **Deutsch (de)**
|
||||||
|
|
||||||
## URL-Struktur
|
## URL-Struktur
|
||||||
|
|
||||||
Alle Routen sind lokalisiert:
|
Alle Routen sind lokalisiert:
|
||||||
|
|
||||||
- `http://localhost:3000/` → Redirect zu `/de` (Standard)
|
- `http://localhost:3000/` → Redirect zu `/en` (Standard)
|
||||||
- `http://localhost:3000/de` → Deutsche Version
|
- `http://localhost:3000/de` → Deutsche Version
|
||||||
- `http://localhost:3000/en` → Englische Version
|
- `http://localhost:3000/en` → Englische Version
|
||||||
- `http://localhost:3000/de/admin` → Admin-Dashboard (Deutsch)
|
- `http://localhost:3000/de/admin` → Admin-Dashboard (Deutsch)
|
||||||
@@ -103,8 +103,8 @@ const genreNameEn = getLocalizedValue(genre.name, 'en'); // "Rock"
|
|||||||
|
|
||||||
**Fallback-Verhalten:**
|
**Fallback-Verhalten:**
|
||||||
1. Versucht die angeforderte Locale (`de` oder `en`)
|
1. Versucht die angeforderte Locale (`de` oder `en`)
|
||||||
2. Fallback zu `de` falls nicht vorhanden
|
2. Fallback zu `en` falls nicht vorhanden
|
||||||
3. Fallback zu `en` falls nicht vorhanden
|
3. Fallback zu `de` falls nicht vorhanden
|
||||||
4. Fallback zum ersten verfügbaren Schlüssel
|
4. Fallback zum ersten verfügbaren Schlüssel
|
||||||
5. Fallback zum übergebenen `fallback`-Parameter
|
5. Fallback zum übergebenen `fallback`-Parameter
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ Bestehende Daten werden automatisch migriert:
|
|||||||
|
|
||||||
Der Proxy (`proxy.ts`) leitet Anfragen automatisch um:
|
Der Proxy (`proxy.ts`) leitet Anfragen automatisch um:
|
||||||
|
|
||||||
- `/` → `/de` (Standard)
|
- `/` → `/en` (Standard)
|
||||||
- Ungültige Locales → 404
|
- Ungültige Locales → 404
|
||||||
- Validiert Locale-Parameter
|
- Validiert Locale-Parameter
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ GET /api/specials?locale=en
|
|||||||
GET /api/news?locale=de
|
GET /api/news?locale=de
|
||||||
```
|
```
|
||||||
|
|
||||||
Falls kein `locale` angegeben wird, wird `de` als Standard verwendet.
|
Falls kein `locale` angegeben wird, wird `en` als Standard verwendet.
|
||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default getRequestConfig(async ({ requestLocale }) => {
|
|||||||
console.log('[i18n/request] incoming requestLocale:', locale);
|
console.log('[i18n/request] incoming requestLocale:', locale);
|
||||||
|
|
||||||
if (!locale || !locales.includes(locale as (typeof locales)[number])) {
|
if (!locale || !locales.includes(locale as (typeof locales)[number])) {
|
||||||
locale = 'de';
|
locale = 'en';
|
||||||
console.log('[i18n/request] falling back to default locale:', locale);
|
console.log('[i18n/request] falling back to default locale:', locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ export function getLocalizedValue(
|
|||||||
if (typeof value === 'object') {
|
if (typeof value === 'object') {
|
||||||
if (value[locale]) return value[locale];
|
if (value[locale]) return value[locale];
|
||||||
|
|
||||||
// Fallback to 'de'
|
|
||||||
if (value['de']) return value['de'];
|
|
||||||
|
|
||||||
// Fallback to 'en'
|
// Fallback to 'en'
|
||||||
if (value['en']) return value['en'];
|
if (value['en']) return value['en'];
|
||||||
|
|
||||||
|
// Fallback to 'de'
|
||||||
|
if (value['de']) return value['de'];
|
||||||
|
|
||||||
// Fallback to first key
|
// Fallback to first key
|
||||||
const keys = Object.keys(value);
|
const keys = Object.keys(value);
|
||||||
if (keys.length > 0) return value[keys[0]];
|
if (keys.length > 0) return value[keys[0]];
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "hoerdle",
|
"name": "hoerdle",
|
||||||
"version": "0.1.0.15",
|
"version": "0.1.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "hoerdle",
|
"name": "hoerdle",
|
||||||
"version": "0.1.0.15",
|
"version": "0.1.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^6.19.0",
|
"@prisma/client": "^6.19.0",
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hoerdle",
|
"name": "hoerdle",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
6
proxy.ts
6
proxy.ts
@@ -2,9 +2,9 @@ import createMiddleware from 'next-intl/middleware';
|
|||||||
import type { NextRequest } from 'next/server';
|
import type { NextRequest } from 'next/server';
|
||||||
|
|
||||||
const i18nMiddleware = createMiddleware({
|
const i18nMiddleware = createMiddleware({
|
||||||
locales: ['de', 'en'],
|
locales: ['en', 'de'],
|
||||||
defaultLocale: 'de',
|
defaultLocale: 'en',
|
||||||
// Wir nutzen überall Locale-Präfixe (`/de`, `/en`)
|
// Wir nutzen überall Locale-Präfixe (`/en`, `/de`)
|
||||||
localePrefix: 'always'
|
localePrefix: 'always'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user