First Commit - Portfolio Page

This commit is contained in:
2025-02-10 00:55:39 +01:00
commit bba0e331a8
239 changed files with 33355 additions and 0 deletions
+175
View File
@@ -0,0 +1,175 @@
// src/i18n/locales/de/blog/index.ts
export const blog = {
meta: {
title: 'Blog - JTL Integration & Digital Solutions',
description: 'Insights und Best Practices zu JTL-WaWi, E-Commerce und digitaler Transformation',
header: {
title: 'Insights & Best Practices',
subtitle: 'Insights und Best Practices zu JTL-WaWi, E-Commerce und digitaler Transformation'
}
},
posts: {
'erp-integration-breuninger': {
title: 'ApparelMagic und TradeByte: Analyse komplexer Integrationen',
date: '2024-02-09',
excerpt: 'Detaillierte Analyse einer E-Commerce-Integration zwischen Apparel Magic und Breuninger via TradeByte',
category: 'System Integration',
tags: ['ERP', 'Apparel Magic', 'TradeByte', 'API Integration', 'Python', 'MariaDB'],
coverImage: '/images/posts/erp-integration-breuninger/cover.jpg',
content: {
intro: {
title: 'Apparel Magic meets Breuninger: Eine technische Analyse der TradeByte-Integration',
description: 'Die Integration von E-Commerce-Systemen mit etablierten Marktplätzen stellt Unternehmen vor besondere Herausforderungen. In diesem Artikel teile ich meine Erfahrungen aus einem komplexen Integrationsprojekt zwischen Apparel Magic als ERP-System und der Breuninger-Plattform über TradeByte.'
},
background: {
title: 'Projekthintergrund',
systems: {
erp: 'Apparel Magic als ERP-System für Produktdaten und Bestandsmanagement',
middleware: 'TradeByte als Middleware für die Breuninger-Plattform'
},
challenges: {
sync: 'Bidirektionale Synchronisation von Bestellungen',
customers: 'Automatisierte Kundenanlage',
delivery: 'Verwaltung von Lieferscheinen',
inventory: 'Bestandsmanagement in Echtzeit'
}
},
tech: {
title: 'Technische Architektur',
components: {
title: 'Zentrale Komponenten'
},
database: {
title: 'Middleware-Datenbank',
description: 'Die MariaDB-Datenbank fungiert als zentraler Datenspeicher für die Integration:'
}
},
api: {
title: 'API-Integrationen',
apparel_magic: {
title: 'Apparel Magic API',
description: 'Die REST-API von Apparel Magic wird für Kundenanlage und Bestandsmanagement verwendet:'
},
tradebyte: {
title: 'TradeByte Integration',
description: 'Die TradeByte-API verwendet eine Kombination aus REST und XML:'
}
},
order_process: {
title: 'Bestellprozess',
steps: {
fetch: 'Regelmäßiger Abruf neuer Bestellungen von TradeByte',
customers: 'Automatische Kundenanlage in Apparel Magic',
process: 'Bestellverarbeitung und Statusaktualisierung',
delivery: 'Generierung und Speicherung von Lieferscheinen'
},
delivery_notes: {
title: 'Lieferschein-Management'
}
},
challenges: {
title: 'Herausforderungen und Lösungen',
status: {
title: '1. Status-Management',
description: 'Eine besondere Herausforderung war das Management von Bestellstatus:'
},
error_handling: {
title: '2. Fehlerbehandlung und Monitoring',
description: 'Robuste Fehlerbehandlung war essentiell für den Produktivbetrieb:'
}
},
best_practices: {
title: 'Best Practices',
api: {
title: '1. API-Kommunikation',
items: {
retry: 'Implementierung von Retry-Mechanismen',
errors: 'Sorgfältiges Error Handling',
logging: 'Ausführliches Logging aller Kommunikation'
}
},
data: {
title: '2. Datenmanagement',
items: {
storage: 'Zentrale Datenhaltung in MariaDB',
transactions: 'Transaktionssicherheit bei kritischen Operationen',
validation: 'Regelmäßige Datenvalidierung'
}
},
automation: {
title: '3. Prozessautomatisierung',
items: {
customers: 'Automatisierte Kundenanlage',
status: 'Automatische Statusaktualisierungen',
delivery: 'Systematisches Lieferschein-Management'
}
}
},
lessons: {
title: 'Lessons Learned',
api: {
title: '1. API-Design',
items: {
docs: 'Gründliche API-Dokumentation ist essentiell',
auth: 'Verständnis der verschiedenen Authentifizierungsmethoden',
limits: 'Berücksichtigung von Rate Limits'
}
},
validation: {
title: '2. Datenvalidierung',
items: {
rules: 'Implementierung strenger Validierungsregeln',
edge_cases: 'Sorgfältige Handhabung von Sonderfällen',
cleanup: 'Automatische Datenbereinigung'
}
},
optimization: {
title: '3. Prozessoptimierung',
items: {
automation: 'Kontinuierliche Verbesserung der Automatisierung',
performance: 'Regelmäßige Performance-Überprüfungen',
monitoring: 'Proaktives Monitoring'
}
}
},
conclusion: {
title: 'Fazit',
requirements: {
understanding: 'Tiefes Verständnis beider Systeme',
implementation: 'Sorgfältige Implementierung der API-Kommunikation',
error_handling: 'Robuste Fehlerbehandlung',
monitoring: 'Kontinuierliches Monitoring'
},
results: 'Die entwickelte Lösung verarbeitet erfolgreich Bestellungen und ermöglicht eine nahtlose Integration zwischen den Systemen. Besonders die automatisierte Kundenanlage und das Lieferschein-Management haben sich als effizienzsteigernd erwiesen.'
}
}
},
},
ui: {
readMore: 'Weiterlesen',
loading: {
posts: 'Blogbeiträge werden geladen...',
post: 'Blogbeitrag wird geladen...'
},
errors: {
posts: 'Fehler beim Laden der Blogbeiträge',
post: 'Der gesuchte Blogbeitrag existiert nicht oder wurde verschoben.'
},
backToBlog: 'Zurück zum Blog',
publishedOn: 'Veröffentlicht am',
category: 'Kategorie',
tags: 'Tags',
notFound: {
title: 'Beitrag nicht gefunden',
message: 'Der gesuchte Blogbeitrag existiert nicht oder wurde verschoben.'
}
},
categories: {
'Integration': 'Integration',
'Entwicklung': 'Entwicklung',
'Automatisierung': 'Automatisierung'
}
} as const;
export type BlogConfig = typeof blog;
export type BlogPost = BlogConfig['posts'][keyof BlogConfig['posts']];
@@ -0,0 +1,138 @@
// src/i18n/locales/de/blog/posts/erp-integration-breuninger.ts
export const erpIntegrationBreuninger = {
posts: {
erp_integration: {
title: 'ApparelMagic und TradeByte: Analyse komplexer Integrationen',
date: '2024-02-09',
excerpt: 'Detaillierte Analyse einer E-Commerce-Integration zwischen Apparel Magic und Breuninger via TradeByte',
category: 'System Integration',
tags: ['ERP', 'Apparel Magic', 'TradeByte', 'API Integration', 'Python', 'MariaDB'],
coverImage: '/images/posts/erp-integration-breuninger/cover.jpg',
intro: {
title: 'Apparel Magic meets Breuninger: Eine technische Analyse der TradeByte-Integration',
description: 'Die Integration von E-Commerce-Systemen mit etablierten Marktplätzen stellt Unternehmen vor besondere Herausforderungen. In diesem Artikel teile ich meine Erfahrungen aus einem komplexen Integrationsprojekt zwischen Apparel Magic als ERP-System und der Breuninger-Plattform über TradeByte.'
},
background: {
title: 'Projekthintergrund',
systems: {
erp: 'Apparel Magic als ERP-System für Produktdaten und Bestandsmanagement',
middleware: 'TradeByte als Middleware für die Breuninger-Plattform'
},
challenges: {
sync: 'Bidirektionale Synchronisation von Bestellungen',
customers: 'Automatisierte Kundenanlage',
delivery: 'Verwaltung von Lieferscheinen',
inventory: 'Bestandsmanagement in Echtzeit'
}
},
tech: {
title: 'Technische Architektur',
components: {
title: 'Zentrale Komponenten'
},
database: {
title: 'Middleware-Datenbank',
description: 'Die MariaDB-Datenbank fungiert als zentraler Datenspeicher für die Integration:'
}
},
api: {
title: 'API-Integrationen',
apparel_magic: {
title: 'Apparel Magic API',
description: 'Die REST-API von Apparel Magic wird für Kundenanlage und Bestandsmanagement verwendet:'
},
tradebyte: {
title: 'TradeByte Integration',
description: 'Die TradeByte-API verwendet eine Kombination aus REST und XML:'
}
},
order_process: {
title: 'Bestellprozess',
steps: {
fetch: 'Regelmäßiger Abruf neuer Bestellungen von TradeByte',
customers: 'Automatische Kundenanlage in Apparel Magic',
process: 'Bestellverarbeitung und Statusaktualisierung',
delivery: 'Generierung und Speicherung von Lieferscheinen'
},
delivery_notes: {
title: 'Lieferschein-Management'
}
},
challenges: {
title: 'Herausforderungen und Lösungen',
status: {
title: '1. Status-Management',
description: 'Eine besondere Herausforderung war das Management von Bestellstatus:'
},
error_handling: {
title: '2. Fehlerbehandlung und Monitoring',
description: 'Robuste Fehlerbehandlung war essentiell für den Produktivbetrieb:'
}
},
best_practices: {
title: 'Best Practices',
api: {
title: '1. API-Kommunikation',
items: {
retry: 'Implementierung von Retry-Mechanismen',
errors: 'Sorgfältiges Error Handling',
logging: 'Ausführliches Logging aller Kommunikation'
}
},
data: {
title: '2. Datenmanagement',
items: {
storage: 'Zentrale Datenhaltung in MariaDB',
transactions: 'Transaktionssicherheit bei kritischen Operationen',
validation: 'Regelmäßige Datenvalidierung'
}
},
automation: {
title: '3. Prozessautomatisierung',
items: {
customers: 'Automatisierte Kundenanlage',
status: 'Automatische Statusaktualisierungen',
delivery: 'Systematisches Lieferschein-Management'
}
}
},
lessons: {
title: 'Lessons Learned',
api: {
title: '1. API-Design',
items: {
docs: 'Gründliche API-Dokumentation ist essentiell',
auth: 'Verständnis der verschiedenen Authentifizierungsmethoden',
limits: 'Berücksichtigung von Rate Limits'
}
},
validation: {
title: '2. Datenvalidierung',
items: {
rules: 'Implementierung strenger Validierungsregeln',
edge_cases: 'Sorgfältige Handhabung von Sonderfällen',
cleanup: 'Automatische Datenbereinigung'
}
},
optimization: {
title: '3. Prozessoptimierung',
items: {
automation: 'Kontinuierliche Verbesserung der Automatisierung',
performance: 'Regelmäßige Performance-Überprüfungen',
monitoring: 'Proaktives Monitoring'
}
}
},
conclusion: {
title: 'Fazit',
requirements: {
understanding: 'Tiefes Verständnis beider Systeme',
implementation: 'Sorgfältige Implementierung der API-Kommunikation',
error_handling: 'Robuste Fehlerbehandlung',
monitoring: 'Kontinuierliches Monitoring'
},
results: 'Die entwickelte Lösung verarbeitet erfolgreich Bestellungen und ermöglicht eine nahtlose Integration zwischen den Systemen. Besonders die automatisierte Kundenanlage und das Lieferschein-Management haben sich als effizienzsteigernd erwiesen.'
}
}
}
};
@@ -0,0 +1,253 @@
// src/i18n/locales/de/blog/posts/fullstack-development-timetracking.ts
export const fullstackDevelopmentTimetracking = {
meta: {
title: 'Fullstack-Entwicklung mit Python und React: Architektur unserer Zeiterfassungslösung',
date: '2024-02-09',
excerpt: 'Eine technische Deep-Dive in die Implementierung einer modernen Zeiterfassungslösung',
category: 'System Architecture',
coverImage: '/images/posts/fullstack-development-timetracking/cover.jpg',
tags: ['Python', 'React', 'TypeScript', 'MSSQL', 'System Design']
},
content: {
intro: {
title: 'Fullstack-Entwicklung mit Python und React: Architektur unserer Zeiterfassungslösung',
description: 'Die Entwicklung einer robusten Zeiterfassungslösung erfordert nicht nur technisches Know-how, sondern auch ein tiefes Verständnis für komplexe Geschäftsregeln und Benutzeranforderungen. In diesem Artikel teile ich unsere Erfahrungen bei der Implementierung einer modernen Fullstack-Zeiterfassungslösung mit Python und React.'
},
systemArchitecture: {
title: 'Systemarchitektur',
frontend: {
title: 'Frontend (Next.js + TypeScript)',
description: 'Die Frontend-Architektur basiert auf Next.js mit TypeScript und folgt einem komponenten-basierten Ansatz:',
code: {
types: `// types/TimeEntry.ts
interface TimeEntry {
id: number;
date: string;
checkIn: string;
checkOut: string | null;
userId: number;
status: 'complete' | 'incomplete';
}`,
component: `// components/TimeEntryForm.tsx
const TimeEntryForm: React.FC<TimeEntryFormProps> = ({ onSubmit }) => {
const [entry, setEntry] = useState<TimeEntry>({
date: new Date().toISOString().split('T')[0],
checkIn: new Date().toLocaleTimeString(),
checkOut: null,
status: 'incomplete'
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateTimeEntry(entry)) return;
try {
await onSubmit(entry);
} catch (error) {
console.error('Error submitting time entry:', error);
}
};
return (
<form onSubmit={handleSubmit} className='space-y-4'>
<DateInput
value={entry.date}
onChange={(date) => setEntry({ ...entry, date })}
/>
<TimeInput
value={entry.checkIn}
onChange={(time) => setEntry({ ...entry, checkIn: time })}
/>
{/* Additional form elements */}
</form>
);
};`
}
},
backend: {
title: 'Backend (Flask + MSSQL)',
description: 'Das Backend verwendet Flask für die API und MSSQL für die Datenpersistenz:',
code: {
models: `# models/time_entry.py
class TimeEntry(db.Model):
__tablename__ = 'Stundenzettel'
id = db.Column('ID', db.Decimal, primary_key=True)
personal_id = db.Column('Personal_ID', db.Decimal)
datum = db.Column('Datum', db.Date)
kommen = db.Column('Kommen', db.Time)
gehen = db.Column('Gehen', db.Time)
@validates('gehen')
def validate_checkout(self, key, value):
if value and value < self.kommen:
raise ValueError('Checkout time cannot be before checkin time')
return value`,
routes: `# routes/time_entries.py
@app.route('/api/time-entries', methods=['POST'])
@jwt_required
def create_time_entry():
data = request.get_json()
user_id = get_jwt_identity()
try:
validate_time_entry_creation(data, user_id)
entry = TimeEntry(
personal_id=user_id,
datum=data['date'],
kommen=data['checkIn'],
gehen=data.get('checkOut')
)
db.session.add(entry)
db.session.commit()
return jsonify(entry.to_dict()), 201
except ValidationError as e:
return jsonify({'error': str(e)}), 400`
}
}
},
businessLogic: {
title: 'Geschäftslogik-Implementierung',
validation: {
title: 'Validierung von Zeiteinträgen',
description: 'Die Validierungslogik stellt sicher, dass alle Geschäftsregeln eingehalten werden:',
code: `def validate_time_entry_creation(data: dict, user_id: int) -> None:
'''Validates a new time entry according to business rules.'''
# Check for existing incomplete entries
incomplete_entry = TimeEntry.query.filter_by(
personal_id=user_id,
gehen=None,
datum=data['date']
).first()
if incomplete_entry:
raise ValidationError('Cannot create new entry while incomplete entry exists')
# Check for time overlap with existing entries
overlapping_entry = TimeEntry.query.filter(
TimeEntry.personal_id == user_id,
TimeEntry.datum == data['date'],
TimeEntry.kommen <= data['checkIn'],
TimeEntry.gehen >= data['checkIn']
).first()
if overlapping_entry:
raise ValidationError('Time entry overlaps with existing entry')`
}
},
databaseDesign: {
title: 'Datenbankdesign',
description: 'Das MSSQL-Datenbankschema ist auf Effizienz und Integrität ausgelegt:',
code: `CREATE TABLE dbo.Stundenzettel (
ID decimal NOT NULL PRIMARY KEY,
Personal_ID decimal,
Datum date,
Kommen time,
Gehen time,
xStatus int,
xBenutzer nvarchar(15),
xDatum datetime,
xVersion timestamp
);
CREATE INDEX idx_personal_datum
ON dbo.Stundenzettel(Personal_ID, Datum);`
},
security: {
title: 'Sicherheitsimplementierung',
authentication: {
title: 'JWT-Authentifizierung',
code: `# auth/jwt_handler.py
from flask_jwt_extended import create_access_token
def authenticate_user(username: str, password: str) -> str:
user = Personal.query.filter_by(
Benutzername=username,
Passwort=password # In production, use proper password hashing
).first()
if not user:
raise AuthenticationError('Invalid credentials')
return create_access_token(identity=user.ID)`
}
},
bestPractices: {
title: 'Best Practices und Learnings',
points: [
{
title: 'Datenvalidierung auf mehreren Ebenen',
items: [
'Frontend-Validierung für sofortiges Feedback',
'Backend-Validierung für Geschäftsregeln',
'Datenbankconstraints für Datenintegrität'
]
},
{
title: 'Fehlerbehandlung',
items: [
'Strukturierte Fehlermeldungen',
'Benutzerfreundliche Fehlermeldungen im Frontend',
'Detailliertes Logging im Backend'
]
},
{
title: 'Performance-Optimierung',
items: [
'Indexierung kritischer Datenbankfelder',
'Frontend-Caching von Zeiteinträgen',
'Lazy Loading für historische Daten'
]
}
]
},
challenges: {
title: 'Herausforderungen und Lösungen',
timezones: {
title: '1. Zeitzonen-Handling',
description: 'Eine besondere Herausforderung war die korrekte Behandlung von Zeitzonen:',
code: `// utils/dateTime.ts
export const formatTimeForDisplay = (time: string): string => {
return new Date(\`1970-01-01T\${time}\`).toLocaleTimeString('de-DE', {
hour: '2-digit',
minute: '2-digit'
});
};
export const formatTimeForAPI = (time: string): string => {
return new Date(\`1970-01-01T\${time}\`).toISOString().split('T')[1];
};`
},
concurrency: {
title: '2. Concurrent Updates',
description: 'Die Behandlung gleichzeitiger Updates erforderte spezielle Aufmerksamkeit:',
code: `from sqlalchemy import and_, or_
def update_time_entry(entry_id: int, data: dict) -> TimeEntry:
entry = TimeEntry.query.filter_by(id=entry_id).with_for_update().first()
if not entry:
raise NotFoundError('Time entry not found')
# Optimistic locking using version field
if entry.xVersion != data['version']:
raise ConcurrencyError('Entry was modified by another user')
entry.gehen = data.get('checkOut')
db.session.commit()
return entry`
},
offline: {
title: '3. Offline-Fähigkeit',
description: 'Für die Offline-Funktionalität implementierten wir eine Service Worker-Strategie:',
code: `// service-worker.ts
const CACHE_NAME = 'timetracking-v1';
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(response => {
return caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});`
}
},
conclusion: {
title: 'Fazit',
description: 'Die Entwicklung einer Zeiterfassungslösung erfordert sorgfältige Planung und Berücksichtigung zahlreicher Geschäftsregeln. Durch den Einsatz moderner Technologien wie Next.js, TypeScript und Flask konnten wir eine robuste und benutzerfreundliche Lösung implementieren.',
keyPoints: [
'Strikte Typisierung mit TypeScript',
'Umfassende Validierungslogik',
'Effizientes Datenbankdesign',
'Benutzerfreundliche Fehlerbehandlung'
],
results: 'Die Lösung ist seit mehreren Monaten erfolgreich im Einsatz und verarbeitet täglich hunderte von Zeiteinträgen zuverlässig.'
}
}
};
@@ -0,0 +1,204 @@
// src/i18n/locales/de/blog/posts/rfid-automation.ts
export const rfidAutomation = {
meta: {
title: 'RFID-Etiketten-Automatisierung: Von Datenbank zum Drucker',
date: '2024-02-09',
excerpt: 'Eine detaillierte technische Analyse der Implementierung eines automatisierten RFID-Etikettendruck-Systems mit Python',
category: 'System Integration',
coverImage: '/images/posts/rfid-automation/cover.jpg',
tags: ['RFID', 'Python', 'ZPL', 'Automation', 'Zebra Printer', 'EPC']
},
content: {
intro: {
title: 'RFID-Etiketten-Automatisierung: Von Datenbank zum Drucker',
description: 'In modernen Logistik- und Retail-Umgebungen ist die effiziente und fehlerfreie Etikettierung von Produkten mit RFID-Tags von entscheidender Bedeutung. In diesem Artikel teile ich meine Erfahrungen bei der Implementierung einer automatisierten Lösung für die Generierung und den Druck von RFID-Etiketten mit Chipkodierung.'
},
requirements: {
title: 'Projekthintergrund',
points: [
'Automatische Generierung von EPC-Codes (Electronic Product Code)',
'Erstellung von ZPL-Code für Zebra-Drucker',
'Direkte Netzwerkkommunikation mit dem Drucker',
'Integration mit bestehenden Produktdaten',
'Fehlerbehandlung und Logging'
]
},
implementation: {
title: 'Technische Umsetzung',
epcGeneration: {
title: 'EPC-Code Generierung',
description: 'Die EPC-Codes werden nach dem SGTIN-Standard (Serialized Global Trade Item Number) generiert:',
code: `def generate_encoded_epc(company_prefix, indicator, item_ref, serial):
sgtin = SGTIN(company_prefix, indicator, item_ref, serial)
return sgtin.encode()`
},
zplTemplates: {
title: 'ZPL-Template Management',
description: 'Für die unterschiedlichen Etikettentypen wurden ZPL-Templates implementiert:',
code: `def generate_zpl_code(artikelnr, description, ean, price, material, water_resistance, glass_type, encoded_epc):
formatted_price = f'{price:.2f}'
return f'''
CT~~CD,~CC^~CT~
^XA
~TA000
~JSN
^LT35
^MNW
^MTT
^PON
^PMN
^LH0,0
^JMA
^PR2,2
~SD23
^JUS
^LRN
^CI27
^PA0,1,1,0
^RS8,,,3
^XZ
^XA
^MMT
^PW413
^LL531
^LS-24
^FT150,57^A0N,33,33^FH\\^CI27^FD{artikelnr}^FS^CI27
^FT44,86^A0N,21,20^FH\\^CI27^FD{description}^FS^CI27
^FT130,141^A0N,50,51^FH\\^CI27^FD{formatted_price} €^FS^CI27
^FT167,175^A0N,21,20^FH\\^CI27^FD{material}^FS^CI27
^FT185,201^A0N,21,20^FH\\^CI27^FD{water_resistance}^FS^CI27
^FT155,227^A0N,21,20^FH\\^CI27^FD{glass_type}^FS^CI27
^BY3,2,113^FT73,420^BEN,,Y,N
^FH\\^FD{ean}^FS
^RFW,H,1,2,1^FD3000^FS
^RFW,H,2,12,1^FD{encoded_epc}^FS
^PQ1,0,1,Y
^XZ'''`
},
printerCommunication: {
title: 'Netzwerkkommunikation mit dem Drucker',
description: 'Die Kommunikation mit dem Zebra-Drucker erfolgt über TCP/IP:',
code: `def send_to_printer(data, printer_ip='192.168.68.50', printer_port=9100):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((printer_ip, printer_port))
sock.sendall(data.encode('utf-8'))
logger.info('Daten erfolgreich an den Drucker gesendet')
except Exception as e:
logger.error(f'Fehler beim Senden der Daten an den Drucker: {e}')`
},
serialNumberManagement: {
title: 'Datenprozessierung und Seriennummernverwaltung',
description: 'Die Verwaltung von Seriennummern ist kritisch für die Eindeutigkeit der EPC-Codes:',
code: `def initialize_serial_number():
global current_serial_number
try:
serial_log_content = SERIAL_NUMBER_LOG_PATH.read_text().strip()
current_serial_number = int(serial_log_content)
except (FileNotFoundError, ValueError):
current_serial_number = START_SERIAL_NUMBER
def get_next_serial_number():
global current_serial_number
current_serial_number += 1
return current_serial_number
def finalize_serial_number():
SERIAL_NUMBER_LOG_PATH.write_text(str(current_serial_number))`
}
},
features: {
title: 'Implementierte Features',
errorHandling: {
title: '1. Robuste Fehlerbehandlung',
points: [
'Validierung der Eingabedaten',
'Überprüfung der Netzwerkverbindung',
'Persistenz von Seriennummern',
'Detailliertes Logging aller Operationen'
]
},
configurability: {
title: '2. Konfigurierbarkeit',
points: [
'Drucker-IP und Port einstellbar',
'Anpassbare ZPL-Templates',
'Flexible EPC-Code-Generierung',
'Konfigurierbare Seriennummernbereiche'
]
},
scalability: {
title: '3. Skalierbarkeit',
points: [
'Batch-Verarbeitung von Produktdaten',
'Parallele Druckaufträge möglich',
'Effizientes Ressourcenmanagement',
'Modularer Code für einfache Erweiterbarkeit'
]
}
},
bestPractices: {
title: 'Best Practices',
dataValidation: {
title: '1. Datenvalidierung',
points: [
'Strict typing für kritische Datenfelder',
'Überprüfung von Pflichtfeldern',
'Format- und Plausibilitätsprüfungen'
]
},
faultTolerance: {
title: '2. Fehlertoleranz',
points: [
'Automatische Wiederholungsversuche',
'Graceful Degradation',
'Detaillierte Fehlerprotokolle'
]
},
maintainability: {
title: '3. Wartbarkeit',
points: [
'Modularer Code-Aufbau',
'Ausführliche Dokumentation',
'Klare Trennung von Konfiguration und Code'
]
}
},
lessonsLearned: {
title: 'Lessons Learned',
zplSpecifics: {
title: '1. ZPL-Spezifika',
points: [
'Genaue Kenntnis der ZPL-Spezifikationen notwendig',
'Sorgfältige Validierung der generierten ZPL-Codes',
'Regelmäßige Tests mit verschiedenen Druckermodellen'
]
},
rfidStandards: {
title: '2. RFID-Standards',
points: [
'Einhaltung der EPC-Standards kritisch',
'Sorgfältige Verwaltung von Seriennummern',
'Validierung der generierten EPC-Codes'
]
},
networkCommunication: {
title: '3. Netzwerkkommunikation',
points: [
'Robuste Fehlerbehandlung bei Netzwerkproblemen',
'Timeouts und Wiederholungsversuche',
'Pufferung von Druckaufträgen'
]
}
},
conclusion: {
title: 'Fazit',
description: 'Die implementierte Lösung ermöglicht eine effiziente und zuverlässige Automatisierung des RFID-Etikettierungsprozesses. Durch die Kombination von EPC-Code-Generierung, ZPL-Template-Management und direkter Druckerkommunikation wurde ein robustes System geschaffen, das sich in der Praxis bewährt hat.',
keyPoints: [
'Gründliche Planung der Systemarchitektur',
'Umfassende Fehlerbehandlung',
'Sorgfältige Dokumentation',
'Regelmäßige Tests und Validierung'
],
results: 'Die Lösung läuft seit mehreren Monaten stabil im Produktivbetrieb und verarbeitet täglich hunderte von Etiketten.'
}
}
};
+99
View File
@@ -0,0 +1,99 @@
export const common = {
// SEO & Meta
siteTitle: 'Damjan Savić - Digital Solutions & JTL Integration',
siteDescription: 'Entwickler individueller Lösungen zur Automatisierung von Prozessen',
// Navigation
nav: {
home: 'Start',
about: 'Über mich',
services: 'Leistungen',
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Kontakt'
},
// Common Actions
actions: {
readMore: 'Weiterlesen',
viewMore: 'Mehr anzeigen',
viewAll: 'Alle anzeigen',
back: 'Zurück',
close: 'Schließen',
submit: 'Absenden',
loading: 'Lädt...'
},
// UI Components
ui: {
published: 'Veröffentlicht am',
lastUpdated: 'Zuletzt aktualisiert am',
category: 'Kategorie',
categories: 'Kategorien',
tag: 'Tag',
tags: 'Tags',
author: 'Autor',
minuteRead: 'Minuten Lesezeit',
tableOfContents: 'Inhaltsverzeichnis'
},
// Error Messages
errors: {
generic: 'Ein Fehler ist aufgetreten',
notFound: 'Seite nicht gefunden',
loading: 'Fehler beim Laden',
return: 'Zurück zur Startseite'
},
// Loading States
loading: {
content: 'Inhalt wird geladen',
page: 'Seite wird geladen',
processing: 'Wird verarbeitet'
},
// Dates
dates: {
months: {
long: [
'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'
],
short: [
'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun',
'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'
]
},
weekdays: {
long: [
'Sonntag', 'Montag', 'Dienstag', 'Mittwoch',
'Donnerstag', 'Freitag', 'Samstag'
],
short: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']
}
},
// Social Media
social: {
followMe: 'Folgen Sie mir auf',
shareOn: 'Teilen auf',
linkedin: 'LinkedIn',
github: 'GitHub',
email: 'E-Mail'
},
// Contact Form
contact: {
title: 'Kontakt',
name: 'Name',
email: 'E-Mail',
message: 'Nachricht',
submit: 'Nachricht senden',
success: 'Ihre Nachricht wurde erfolgreich gesendet',
error: 'Es gab einen Fehler beim Senden Ihrer Nachricht'
},
// Accessibility
a11y: {
skipToContent: 'Zum Hauptinhalt springen',
menuOpen: 'Menü öffnen',
menuClose: 'Menü schließen',
darkMode: 'Dark Mode umschalten',
carousel: {
next: 'Nächstes Bild',
previous: 'Vorheriges Bild'
}
}
} as const;
export type CommonTranslations = typeof common;
+9
View File
@@ -0,0 +1,9 @@
const cookiebanner = {
cookies: {
message: "Diese Website verwendet Cookies, um Ihr Browsing-Erlebnis zu verbessern. Die Daten werden nicht an Dritte weitergegeben.",
accept: "Cookies akzeptieren",
decline: "Ablehnen"
}
};
export default cookiebanner;
+40
View File
@@ -0,0 +1,40 @@
// src/i18n/locales/de/footer.ts
const footer = {
sections: {
contact: {
title: "Kontakt",
email: "info@damjan-savic.com",
location: "Köln, Deutschland",
aria: {
emailLink: "E-Mail senden",
locationText: "Standort"
}
},
navigation: {
title: "Navigation",
links: {
portfolio: "Portfolio",
blog: "Blog",
about: "Über mich",
contact: "Kontakt"
}
},
social: {
title: "Social Media",
aria: {
linkedin: "Besuchen Sie mein LinkedIn Profil",
github: "Besuchen Sie mein GitHub Profil"
}
}
},
legal: {
copyright: "Alle Rechte vorbehalten",
links: {
privacy: "Datenschutz",
terms: "Impressum"
}
}
} as const;
export default footer;
export type FooterTranslations = typeof footer;
+109
View File
@@ -0,0 +1,109 @@
// src/i18n/locales/de/index.ts
// Blog post translations
import { erpIntegrationBreuninger } from './blog/posts/erp-integration-breuninger';
import { fullstackDevelopmentTimetracking } from './blog/posts/fullstack-development-timetracking';
import { rfidAutomation as blogRfidAutomation } from './blog/posts/rfid-automation';
import { blog } from './blog/index';
// Page translations
import { about } from './pages/about/index';
import { contact } from './pages/contact/index';
import { dashboard } from './pages/dashboard';
import { home } from './pages/home';
import { login } from './pages/login';
import { notfound } from './pages/notfound';
import { portfolio as portfolioPage } from './pages/portfolio';
import { privacy } from './pages/privacy';
import { terms } from './pages/terms';
// Portfolio project translations
import { aiDataReader } from './portfolio/projects/ai-data-reader';
import { portfolio } from './portfolio/index';
// Common translations and configurations
import { common } from './common';
import { meta } from './meta';
import { navigation } from './navigation';
// Footer translations
import footer from './footer';
// Zusammenführung aller Übersetzungsobjekte
const translations = {
// Pages
pages: {
about,
contact,
dashboard,
home,
login,
notfound,
portfolio: portfolioPage,
privacy,
terms,
},
// Blog
blog: {
...blog,
posts: {
erpIntegrationBreuninger,
fullstackDevelopmentTimetracking,
rfidAutomation: blogRfidAutomation,
},
},
// Portfolio
portfolio: {
...portfolio,
projects: {
aiDataReader,
},
},
// Footer
footer,
// Gemeinsame Konfigurationen
common: {
...common,
cookies: {
message: "Diese Website verwendet Cookies, um Ihr Browsing-Erlebnis zu verbessern. Die Daten werden nicht an Dritte weitergegeben.",
accept: "Cookies akzeptieren",
decline: "Ablehnen"
}
},
meta,
navigation,
} as const;
// Default-Export: komplettes Übersetzungsobjekt
export default translations;
// Typdefinition der Übersetzungen
export type Translations = typeof translations;
// Re-Exports für den direkten Zugriff auf einzelne Module
export {
// Pages
about,
contact,
dashboard,
home,
login,
notfound,
portfolioPage as portfolioPageTranslations,
privacy,
terms,
// Blog
blog,
erpIntegrationBreuninger,
fullstackDevelopmentTimetracking,
blogRfidAutomation as blogRfidAutomationPost,
// Portfolio
portfolio,
aiDataReader,
// Footer
footer,
// Common
common,
meta,
navigation,
};
+93
View File
@@ -0,0 +1,93 @@
export const meta = {
site: {
name: 'Damjan Savić',
title: 'Damjan Savić - Digital Solutions & JTL Integration',
subtitle: 'Entwickler individueller Lösungen zur Automatisierung von Prozessen',
description: 'Mit einem Hintergrund in der Softwareentwicklung und Expertise in der digitalen Transformation unterstütze ich Unternehmen bei der Optimierung und Automatisierung ihrer Geschäftsprozesse.',
keywords: [
'JTL Integration',
'E-Commerce Lösungen',
'Prozessautomatisierung',
'Digitale Beratung',
'ERP Systeme',
'Python Entwicklung',
'Systemintegration',
'Digitales Marketing'
].join(', ')
},
company: {
name: 'CoderConda',
shortName: 'CoderConda',
description: 'Ihr JTL-Servicepartner für schnelle, verbindliche und kosteneffiziente Lösungen.',
address: 'Rotdornallee',
city: 'Köln',
postalCode: '50999',
country: 'Deutschland',
phone: '+49 175 695 0979',
email: 'info@damjan-savic.com',
website: 'www.damjan-savic.com'
},
author: {
name: 'Damjan Savić',
role: 'Consultant Digital Solutions',
company: 'CoderConda',
location: 'Köln, Deutschland',
email: 'info@damjan-savic.com',
website: 'https://www.damjan-savic.com',
languages: [
{ code: 'en', level: 'C2', name: 'Englisch' },
{ code: 'sr', level: 'C2', name: 'Serbisch' },
{ code: 'de', level: 'C2', name: 'Deutsch' },
{ code: 'fr', level: 'B2', name: 'Französisch' },
{ code: 'es', level: 'B2', name: 'Spanisch' },
{ code: 'ru', level: 'A1', name: 'Russisch' }
]
},
social: {
linkedin: 'https://www.linkedin.com/in/damjansavic/',
github: 'https://github.com/damjansavic',
email: 'info@damjan-savic.com'
},
expertise: {
areas: [
'JTL Integration & Beratung',
'Prozessautomatisierung',
'E-Commerce Entwicklung',
'Systemintegration',
'ERP-Systeme',
'Digitale Transformation'
],
technologies: [
'Python',
'React/Next.js',
'MariaDB',
'Docker',
'JTL-WaWi',
'Shopify',
'Shopware'
]
},
seo: {
defaultLanguage: 'de',
alternateLanguages: ['en', 'sr'],
robots: 'index, follow',
googleSiteVerification: '', // Falls benötigt
og: {
type: 'website',
locale: 'de_DE',
siteName: 'Damjan Savić - Digital Solutions',
images: {
url: '/images/og-image.jpg',
width: 1200,
height: 630,
alt: 'Damjan Savić - Digital Solutions & JTL Integration'
}
},
twitter: {
card: 'summary_large_image',
site: '@damjansavic',
creator: '@damjansavic'
}
}
} as const;
export type MetaConfig = typeof meta;
+79
View File
@@ -0,0 +1,79 @@
// C:\Development\Damjan Savic\Portfolio\src\i18n\locales\de\navigation.ts
export const navigation = {
// Hauptnavigation
main: {
home: 'Startseite',
about: 'Über mich',
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Kontakt'
},
// Dashboard und Admin
admin: {
login: 'Anmelden',
dashboard: 'Dashboard',
logout: 'Abmelden'
},
// Footer Navigation
footer: {
legal: {
privacy: 'Datenschutz',
terms: 'AGB',
imprint: 'Impressum'
},
sections: {
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Kontakt'
}
},
// Seitennavigation
sections: {
experience: 'Erfahrung',
skills: 'Fähigkeiten',
projects: 'Projekte',
about: 'Über mich'
},
// Breadcrumbs und zurück-Navigation
navigation: {
backTo: {
home: 'Zurück zur Startseite',
portfolio: 'Zurück zum Portfolio',
blog: 'Zurück zum Blog'
},
breadcrumbs: {
home: 'Startseite',
portfolio: 'Portfolio',
blog: 'Blog',
about: 'Über mich',
contact: 'Kontakt'
}
},
// Mobile Navigation
mobile: {
menu: 'Menü',
close: 'Schließen',
open: 'Menü öffnen'
},
// URLs (für dynamische Route-Generierung)
urls: {
home: '/',
about: '/about',
portfolio: '/portfolio',
blog: '/blog',
contact: '/contact',
login: '/login',
dashboard: '/dashboard',
privacy: '/privacy',
terms: '/terms'
},
// Meta-Informationen für Navigation
meta: {
main: 'Hauptnavigation',
footer: 'Footer Navigation',
social: 'Social Media Navigation',
legal: 'Rechtliche Navigation'
}
} as const;
export type NavigationConfig = typeof navigation;
+33
View File
@@ -0,0 +1,33 @@
export const hero = {
// Navigation/Header
aboutMe: 'ÜBER MICH',
// Main Section
title: 'Digital Solutions Experte',
description: 'Mit einem Hintergrund in Softwareentwicklung und Expertise in digitaler Transformation helfe ich Unternehmen ihre Prozesse durch innovative Lösungen zu optimieren und zu automatisieren.',
// Expertise Areas
expertise: {
processAutomation: {
title: 'Prozessautomatisierung',
description: 'Entwicklung effizienter automatisierter Workflows'
},
systemIntegration: {
title: 'Systemintegration',
description: 'Verbindung und Optimierung von Geschäftssystemen'
},
customDevelopment: {
title: 'Individuelle Entwicklung',
description: 'Erstellung maßgeschneiderter Softwarelösungen'
}
},
// Languages
languages: {
english: 'Englisch',
serbian: 'Serbisch',
german: 'Deutsch',
french: 'Französisch',
spanish: 'Spanisch',
russian: 'Russisch'
}
} as const;
// Type für Typsicherheit
export type HeroTranslations = typeof hero;
+24
View File
@@ -0,0 +1,24 @@
import { hero } from './hero';
import { journey } from './journey';
import { schema } from './schema';
import { skillbar } from './skillbar';
import { skillgroup } from './skillgroup';
import { skills } from './skills';
import { workflow } from './workflow';
export const about = {
hero,
journey,
schema,
skillbar,
skillgroup,
skills,
workflow
} as const;
// Typen exportieren
export type { HeroTranslations } from './hero';
export type { JourneyTranslations } from './journey';
export type { SchemaTranslations } from './schema';
export type { SkillBarTranslations } from './skillbar';
export type { SkillGroupTranslations } from './skillgroup';
export type { SkillsTranslations } from './skills';
export type { WorkflowTranslations } from './workflow';
@@ -0,0 +1,95 @@
export const journey = {
// Header
title: 'Beruflicher Werdegang',
subtitle: 'Von digitalen Medien zu Unternehmenslösungen',
// Education Section
education: {
title: 'Ausbildung',
degrees: {
masters: {
degree: 'M.A. Softwareentwicklung',
university: 'Middlesex University, London',
period: '2020 - 2022'
},
bachelors: {
degree: 'B.A. Cross-Media Produktion',
university: 'Middlesex University, London',
period: '2018 - 2020'
}
}
},
// Languages Section
languages: {
title: 'Sprachen',
items: {
english: {
name: 'Englisch',
level: 'C2'
},
serbian: {
name: 'Serbisch',
level: 'C2'
},
german: {
name: 'Deutsch',
level: 'C2'
},
french: {
name: 'Französisch',
level: 'B2'
},
spanish: {
name: 'Spanisch',
level: 'B2'
},
russian: {
name: 'Russisch',
level: 'A1'
}
}
},
// Work History
work: {
positions: [
{
period: '08/2023 - Heute',
company: 'Ritter Digital GmbH',
title: 'Digital Solutions Consultant',
location: 'Oberhausen',
highlights: [
'ERP-Beratung und -Implementierung (JTL WaWi)',
'Prozessautomatisierung & Full-Stack-Entwicklung',
'RFID-Technologie & Automatisierung',
'Lead-Generierung & -Management',
'KI-gestütztes Content-Management'
]
},
{
period: '02/2023 - 08/2023',
company: 'Joyce & Girls Co AG',
title: 'ERP Integration Specialist',
location: 'Köln',
highlights: [
'Komplexe Systemintegration (Apparel Magic, TradeByte)',
'Server-Administration und Automatisierung',
'Datenbank- und API-Entwicklung',
'Digitales Marketing und Kampagnenanalyse'
]
},
{
period: '08/2022 - 01/2023',
company: 'Magnarius',
title: 'RPA Developer & E-Commerce Manager',
location: 'Bergisch Gladbach',
highlights: [
'Shopware 6 Entwicklung und JTL-Integration',
'Google Ads Automatisierung',
'CMS-Management und -Optimierung',
'SEO-Strategieumsetzung'
]
}
]
}
} as const;
// Type für Typsicherheit
export type JourneyTranslations = typeof journey;
+31
View File
@@ -0,0 +1,31 @@
export const schema = {
page: {
name: 'Über Damjan Savić',
description: 'Erfahren Sie mehr über Damjan Savić, einen zertifizierten JTL-Experten mit umfassender Erfahrung in E-Commerce und Warenwirtschaftslösungen.'
},
person: {
jobTitle: 'JTL Integrations-Experte',
description: 'Mit umfangreicher Erfahrung in der Integration und Optimierung von E-Commerce-Systemen unterstütze ich Unternehmen bei der digitalen Transformation ihrer Geschäftsprozesse.',
languages: {
english: 'Englisch',
serbian: 'Serbisch',
german: 'Deutsch',
french: 'Französisch',
spanish: 'Spanisch',
russian: 'Russisch'
},
skills: {
python: 'Python',
googleAds: 'Google Ads',
metaAds: 'Meta Ads',
shopware: 'Shopware',
shopify: 'Shopify',
wooCommerce: 'WooCommerce',
jtlWawi: 'JTL WAWI',
serverAdmin: 'Server-Administration',
airflow: 'AirFlow'
}
}
} as const;
// Type für Typsicherheit
export type SchemaTranslations = typeof schema;
@@ -0,0 +1,13 @@
export const skillbar = {
// Accessibility labels
ariaLabel: {
skillLevel: 'Fähigkeitsniveau',
progressBar: 'Fortschrittsbalken'
},
// Screen reader text
screenReader: {
progress: '{{level}} Prozent Fortschritt für {{skill}}'
}
} as const;
// Type für Typsicherheit
export type SkillBarTranslations = typeof skillbar;
@@ -0,0 +1,63 @@
export const skillgroup = {
// Kategorien
categories: {
development: 'Entwicklung',
ecommerce: 'E-Commerce',
marketing: 'Marketing',
automation: 'Automatisierung',
languages: 'Programmiersprachen',
databases: 'Datenbanken'
},
// Skills nach Kategorien
skills: {
development: {
frontend: 'Frontend-Entwicklung',
backend: 'Backend-Entwicklung',
fullstack: 'Full-Stack-Entwicklung',
api: 'API-Entwicklung',
testing: 'Software-Testing'
},
ecommerce: {
jtl: 'JTL WaWi',
shopware: 'Shopware',
shopify: 'Shopify',
woocommerce: 'WooCommerce',
magento: 'Magento'
},
marketing: {
seo: 'Suchmaschinenoptimierung',
sea: 'Suchmaschinenwerbung',
analytics: 'Web-Analyse',
googleAds: 'Google Ads',
metaAds: 'Meta Ads'
},
automation: {
rpa: 'Robotergestützte Prozessautomatisierung',
workflow: 'Workflow-Automatisierung',
cicd: 'CI/CD',
testing: 'Test-Automatisierung',
deployment: 'Deployment-Automatisierung'
},
languages: {
python: 'Python',
javascript: 'JavaScript',
typescript: 'TypeScript',
php: 'PHP',
sql: 'SQL'
},
databases: {
mysql: 'MySQL',
postgresql: 'PostgreSQL',
mongodb: 'MongoDB',
redis: 'Redis',
elasticsearch: 'Elasticsearch'
}
},
// Accessibility
ariaLabels: {
skillGroup: 'Fähigkeitsgruppe',
skillList: 'Liste der Fähigkeiten in dieser Kategorie'
}
} as const;
// Type für Typsicherheit
export type SkillGroupTranslations = typeof skillgroup;
+46
View File
@@ -0,0 +1,46 @@
// de/pages/about/skills.ts
export const skills = {
title: 'Fähigkeiten',
skillGroups: [
{
category: 'Entwicklung',
items: [
{ name: 'Python', level: 90 },
{ name: 'Google Ads', level: 85 },
{ name: 'Meta Ads', level: 85 }
]
},
{
category: 'E-Commerce',
items: [
{ name: 'Shopware', level: 85 },
{ name: 'Shopify', level: 85 },
{ name: 'WooCommerce', level: 85 }
]
},
{
category: 'Systemadministration',
items: [
{ name: 'JTL WAWI', level: 85 },
{ name: 'Server', level: 75 },
{ name: 'AirFlow', level: 60 }
]
}
],
ui: {
percentage: 'Prozent',
levelLabel: 'Niveau',
skillLevel: '{{level}}% Beherrschung in {{skill}}'
},
aria: {
skillGroup: 'Fähigkeitsgruppe für {{category}}',
skillBar: 'Fortschrittsbalken für {{skill}}',
skillIcon: 'Symbol für {{category}}',
selectSkill: 'Fähigkeit auswählen'
},
screenReader: {
skillProgress: '{{skill}} mit einem Niveau von {{level}} Prozent'
}
} as const;
export type SkillsTranslations = typeof skills;
@@ -0,0 +1,44 @@
export const workflow = {
// Seitentitel
title: 'MEIN WORKFLOW',
description: 'Systematischer Ansatz zur Softwareentwicklung durch definierte Schritte',
// Workflow-Schritte
steps: [
{
number: '01',
title: 'ANFORDERUNGSANALYSE'
},
{
number: '02',
title: 'ABFRAGE VON DEADLINES UND EINSCHRÄNKUNGEN'
},
{
number: '03',
title: 'EINRICHTUNG DER ENTWICKLUNGSUMGEBUNG'
},
{
number: '04',
title: 'PROGRAMMIERUNG'
},
{
number: '05',
title: 'TESTEN DER ERGEBNISSE'
},
{
number: '06',
title: 'SUPPORT UND SKALIERUNG DES CODES'
}
],
// Aria Labels für Barrierefreiheit
aria: {
workflowSection: 'Workflow-Prozess',
stepNumber: 'Schritt {{number}}',
stepDescription: 'Workflow-Schritt: {{title}}'
},
// Screen Reader Texte
screenReader: {
stepProgress: 'Schritt {{number}} von {{total}}: {{title}}'
}
} as const;
// Type für Typsicherheit
export type WorkflowTranslations = typeof workflow;
@@ -0,0 +1,39 @@
export const contactform = {
// Formular Header
title: 'Kontaktieren Sie mich',
description: 'Haben Sie Fragen oder möchten Sie zusammenarbeiten? Schreiben Sie mir eine Nachricht.',
// Formularfelder
name: {
label: 'Name',
placeholder: 'Ihr vollständiger Name'
},
email: {
label: 'E-Mail',
placeholder: 'ihre.email@beispiel.de'
},
message: {
label: 'Nachricht',
placeholder: 'Ihre Nachricht an mich...'
},
// Button
submit: 'Nachricht senden',
// Statusmeldungen
successMessage: 'Vielen Dank für Ihre Nachricht! Ich werde mich so schnell wie möglich bei Ihnen melden.',
errorMessage: 'Entschuldigung, beim Senden Ihrer Nachricht ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
// Fehlermeldungen
errors: {
nameRequired: 'Bitte geben Sie Ihren Namen ein',
emailRequired: 'Bitte geben Sie Ihre E-Mail-Adresse ein',
emailInvalid: 'Bitte geben Sie eine gültige E-Mail-Adresse ein',
messageRequired: 'Bitte geben Sie eine Nachricht ein'
},
// Aria Labels
aria: {
form: 'Kontaktformular',
submitting: 'Formular wird gesendet',
successAlert: 'Erfolgsmeldung',
errorAlert: 'Fehlermeldung'
}
} as const;
// Type für Typsicherheit
export type ContactFormTranslations = typeof contactform;
@@ -0,0 +1,25 @@
export const contactinfo = {
// Header
title: 'Kontaktinformationen',
description: 'Sie können mich über folgende Wege erreichen',
// Kontaktmethoden Labels
addressLabel: 'Bürostandort',
phoneLabel: 'Telefon',
emailLabel: 'E-Mail',
// Kontaktinformationen
address: 'Rotdornallee, Köln',
phone: '+49 175 695 0979',
email: 'info@damjan-savic.com',
// Zusätzliche Informationen
availabilityNote: 'Geschäftszeiten: Montag bis Freitag, 9:00 - 17:00 Uhr',
// Aria Labels
aria: {
contactCard: 'Kontaktinformationskarte',
addressLink: 'Öffne Standort in Google Maps',
phoneLink: 'Anrufen',
emailLink: 'E-Mail senden',
externalLink: 'Öffnet in neuem Tab'
}
} as const;
// Type für Typsicherheit
export type ContactInfoTranslations = typeof contactinfo;
@@ -0,0 +1,71 @@
// src/i18n/locales/de/pages/contact/index.ts
export const contact = {
breadcrumb: "KONTAKT",
hero: {
title: "Lassen Sie uns zusammenarbeiten",
subtitle: "Sie haben ein Projekt im Sinn? Lassen Sie uns besprechen, wie wir Ihnen bei der Erreichung Ihrer Ziele helfen können."
},
contactInfo: {
title: "Kontaktinformationen",
description: "Sie können mich über folgende Wege erreichen",
address: {
label: "Bürostandort",
value: "Rotdornallee, Köln"
},
phone: {
label: "Telefon",
value: "+49 175 695 0979"
},
email: {
label: "E-Mail",
value: "info@damjan-savic.com"
},
availabilityNote: "Geschäftszeiten: Montag bis Freitag, 9:00 - 17:00 Uhr",
aria: {
contactCard: "Kontaktinformationskarte",
addressLink: "Öffne Standort in Google Maps",
phoneLink: "Anrufen",
emailLink: "E-Mail senden",
externalLink: "Öffnet in neuem Tab"
}
},
contactForm: {
title: "Kontaktieren Sie mich",
description: "Haben Sie Fragen oder möchten Sie zusammenarbeiten? Schreiben Sie mir eine Nachricht.",
name: {
label: "Name",
placeholder: "Ihr vollständiger Name"
},
email: {
label: "E-Mail",
placeholder: "ihre.email@beispiel.de"
},
message: {
label: "Nachricht",
placeholder: "Ihre Nachricht an mich..."
},
submit: "Nachricht senden",
successMessage: "Vielen Dank für Ihre Nachricht! Ich werde mich so schnell wie möglich bei Ihnen melden.",
errorMessage: "Entschuldigung, beim Senden Ihrer Nachricht ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
errors: {
nameRequired: "Bitte geben Sie Ihren Namen ein",
emailRequired: "Bitte geben Sie Ihre E-Mail-Adresse ein",
emailInvalid: "Bitte geben Sie eine gültige E-Mail-Adresse ein",
messageRequired: "Bitte geben Sie eine Nachricht ein"
},
aria: {
form: "Kontaktformular",
submitting: "Formular wird gesendet",
successAlert: "Erfolgsmeldung",
errorAlert: "Fehlermeldung"
}
}
} as const;
export type ContactTranslations = typeof contact;
export default {
pages: {
contact: contact
}
};
+76
View File
@@ -0,0 +1,76 @@
// src/i18n/locales/de/pages/dashboard.ts
export const dashboard = {
// SEO
seo: {
title: 'Analytics Dashboard',
description: 'Website-Analysedashboard'
},
// Hauptüberschriften
header: {
title: 'Analytics Dashboard',
activeUsers: 'aktive Nutzer'
},
// Metrikkarten
metrics: {
pageViews: {
title: 'Seitenaufrufe',
perMinute: 'pro Minute'
},
uniqueVisitors: {
title: 'Eindeutige Besucher',
currentlyActive: 'aktuell aktiv'
},
conversions: {
title: 'Konversionen',
rate: 'Konversionsrate'
},
timeOnSite: {
title: 'Durchschn. Besuchszeit',
bounceRate: 'Absprungrate'
}
},
// Top-Seiten Bereich
topPages: {
title: 'Top-Seiten',
columns: {
path: 'Pfad',
views: 'Aufrufe',
change: 'Änderung'
}
},
// Event-Tracking Bereich
events: {
title: 'Event-Tracking',
types: {
contactForm: 'Kontaktformular Absendung',
portfolioView: 'Portfolio Ansicht',
cvDownload: 'Lebenslauf Download',
blogRead: 'Blog Gelesen'
}
},
// Statusmeldungen
status: {
loading: 'Lade Dashboard...',
error: 'Fehler beim Laden der Daten',
notAuthenticated: 'Bitte melden Sie sich an'
},
// Sonstiges
misc: {
viewMore: 'Mehr anzeigen',
refresh: 'Aktualisieren',
period: {
today: 'Heute',
yesterday: 'Gestern',
last7Days: 'Letzte 7 Tage',
last30Days: 'Letzte 30 Tage',
thisMonth: 'Dieser Monat',
lastMonth: 'Letzter Monat'
}
},
// Trends und Änderungen
trends: {
increase: 'Zunahme',
decrease: 'Abnahme',
noChange: 'Keine Änderung'
}
};
+9
View File
@@ -0,0 +1,9 @@
// src/i18n/locales/de/pages/home/about.ts
export const about = {
title: 'Über Mich',
content: 'Als Berater im Bereich der Digitalisierung helfe ich Unternehmen, ihre Abläufe durch moderne Software zu verbessern. Ich entwickle Lösungen zur Verbindung von Warenwirtschaftssystemen, Programme zur Automatisierung von Arbeitsabläufen und RFID-Anwendungen zur besseren Warenverfolgung. Bei der Ritter Digital GmbH arbeite ich mit JTL-Software und entwickle individuelle Programmlösungen. Ein weiteres Projekt war die Verbindung der Systeme von Breuninger mit Apparel Magic über TB.One. Mein Ziel ist es, Unternehmen durch Software effizienter zu machen.',
image: {
alt: 'Portrait von Damjan Savić'
}
} as const;
export type AboutTranslations = typeof about;
@@ -0,0 +1,77 @@
// src/i18n/locales/de/pages/home/experience.ts
export const experience = {
title: 'Berufserfahrung',
navigation: {
prev: '←',
next: '→'
},
positions: [
{
role: 'Consultant Digital Solutions & Developer',
company: 'RITTER Gesellschaft für digitale Geschäftsprozesse mbH',
period: '08/2023 - HEUTE',
highlights: [
'JTL WaWi, WMS und POS Beratung & Implementierung',
'Python-basierte Automationslösungen',
'RFID-Systeme und GUI-Entwicklung',
'KI & Business Intelligence'
]
},
{
role: 'ERP-Integrationsspezialist & E-Commerce-Entwickler',
company: 'Joyce & Girls',
period: '01/2023 - 08/2023',
highlights: [
'ApparelMagic & TradeByte Integration',
'MariaDB Middleware-Entwicklung',
'Windows Server Administration',
'Shopify-Optimierung'
]
},
{
role: 'RPA Developer & E-Commerce Manager',
company: 'C&S Marketing',
period: '08/2022 - 01/2023',
highlights: [
'Shopware 6 & JTL Integration',
'Python Automatisierung',
'Google Ads Optimierung',
'CMS Management'
]
},
{
role: 'E-Commerce Developer',
company: 'Brands Club GmbH',
period: '08/2021 - 07/2022',
highlights: [
'Shopify & JTL Integration',
'Server Administration',
'Content Production',
'Marketing Automation'
]
},
{
role: 'E-Commerce Developer',
company: 'Feine Uhren Eupen',
period: '01/2021 - 08/2021',
highlights: [
'Shopware 5 Development',
'Produktfotografie',
'Sales im Luxusuhrensegment',
'E-Commerce Management'
]
},
{
role: 'Online Marketing Manager',
company: 'Ufer8, Ambis, Teatro & Die Halle Tor 2',
period: '01/2018 - 12/2020',
highlights: [
'Social Media Content',
'Event Marketing',
'Veranstaltungsorganisation',
'Marketing Automation'
]
}
]
} as const;
export type ExperienceTranslations = typeof experience;
@@ -0,0 +1,27 @@
// src/i18n/locales/de/pages/home/expertise.ts
export const expertise = {
title: 'Bereiche meiner Expertise',
areas: [
{
title: 'ERP Integration',
description: 'Expert für JTL-Wawi Implementierung, Konfiguration und Optimierung. Spezialisiert auf Warenwirtschaftssysteme und POS-Integration.',
skills: ['JTL-Wawi', 'JTL-WMS', 'JTL-POS', 'Apparel Magic']
},
{
title: 'Entwicklung',
description: 'Full-Stack Entwicklung mit Fokus auf Python-Automatisierung, React Frontends und Datenbankdesign.',
skills: ['Python', 'React/Next.js', 'MariaDB', 'Docker']
},
{
title: 'E-Commerce',
description: 'Umfangreiche Erfahrung mit verschiedenen E-Commerce-Plattformen und Marktplatz-Integrationen.',
skills: ['Shopify', 'Shopware', 'WooCommerce', 'API Integration']
},
{
title: 'Digitales Marketing',
description: 'Strategischer Ansatz im digitalen Marketing mit Fokus auf Automatisierung und Analyse.',
skills: ['Google Ads', 'Meta Ads', 'SEO', 'Analytics']
}
]
} as const;
export type ExpertiseTranslations = typeof expertise;
+29
View File
@@ -0,0 +1,29 @@
// src/i18n/locales/de/pages/home/hero.ts
export const hero = {
title: 'SOFTWARE ENGINEER',
name: 'DAMJAN SAVIĆ',
cta: 'KONTAKT AUFNEHMEN',
image: {
alt: 'Portrait von Damjan Savić'
},
social: {
getInTouch: 'Kontaktieren Sie mich',
linkedin: {
title: 'Besuchen Sie mein LinkedIn Profil'
},
github: {
title: 'Besuchen Sie mein GitHub Profil'
},
email: {
title: 'Senden Sie mir eine E-Mail'
}
},
navigation: {
experience: 'ERFAHRUNG',
skills: 'FÄHIGKEITEN',
projects: 'PROJEKTE',
about: 'ÜBER MICH'
}
} as const;
export type HeroTranslations = typeof hero;
+18
View File
@@ -0,0 +1,18 @@
// src/i18n/locales/de/pages/home/index.ts
import { hero } from './hero';
import { about } from './about';
import { experience } from './experience';
import { expertise } from './expertise';
import { skills } from './skills';
import { projects } from './projects';
export const home = {
hero,
about,
experience,
expertise,
skills,
projects
} as const;
export type HomeTranslations = typeof home;
@@ -0,0 +1,10 @@
// src/i18n/locales/de/pages/home/projects.ts
export const projects = {
title: 'Portfolio',
viewAll: 'Alle Projekte →',
loading: 'Projekte werden geladen...',
error: {
loading: 'Fehler beim Laden der Projekte'
}
} as const;
export type ProjectsTranslations = typeof projects;
+41
View File
@@ -0,0 +1,41 @@
// src/i18n/locales/de/pages/home/skills.ts
export const skills = {
title: 'Fähigkeiten',
skills: [
{
name: 'ERP',
level: 90,
description: 'Enterprise Resource Planning'
},
{
name: 'Datenbank',
level: 85,
description: 'Datenbankentwicklung und -administration'
},
{
name: 'E-Commerce',
level: 95,
description: 'Online-Handel und Plattformen'
},
{
name: 'Python',
level: 80,
description: 'Programmiersprache Python'
},
{
name: 'React',
level: 75,
description: 'Frontend-Entwicklung mit React'
},
{
name: 'Server',
level: 70,
description: 'Server-Administration'
}
],
aria: {
skillLevel: 'Fähigkeitsniveau',
selectSkill: 'Fähigkeit auswählen'
}
} as const;
export type SkillsTranslations = typeof skills;
+54
View File
@@ -0,0 +1,54 @@
// src/i18n/locales/de/pages/login.ts
export const login = {
// SEO
seo: {
title: 'Login',
description: 'Anmelden für Zugriff auf das Dashboard'
},
// Hauptüberschrift
header: {
title: 'Im Dashboard anmelden'
},
// Formular
form: {
// Felder
email: {
label: 'E-Mail-Adresse',
placeholder: 'ihre.email@beispiel.de'
},
password: {
label: 'Passwort',
placeholder: 'Ihr Passwort'
},
// Buttons
submit: {
default: 'Anmelden',
loading: 'Anmeldung läuft...'
},
// Fehlermeldungen
errors: {
default: 'Ein Fehler ist aufgetreten',
invalidCredentials: 'Ungültige Anmeldedaten',
emailRequired: 'Bitte geben Sie Ihre E-Mail-Adresse ein',
passwordRequired: 'Bitte geben Sie Ihr Passwort ein',
emailInvalid: 'Bitte geben Sie eine gültige E-Mail-Adresse ein'
}
},
// Links und Hilfe
help: {
forgotPassword: 'Passwort vergessen?',
needHelp: 'Benötigen Sie Hilfe?',
contactSupport: 'Support kontaktieren'
},
// Statusmeldungen
status: {
authenticating: 'Authentifizierung...',
success: 'Erfolgreich angemeldet',
redirecting: 'Weiterleitung zum Dashboard...'
},
// Sicherheitshinweise
security: {
secureConnection: 'Sichere Verbindung',
privacyNote: 'Ihre Daten werden verschlüsselt übertragen'
}
};
+19
View File
@@ -0,0 +1,19 @@
// src/i18n/locales/de/pages/notfound.ts
export const notfound = {
// SEO
seo: {
title: '404 - Seite nicht gefunden',
description: 'Die gesuchte Seite existiert nicht.'
},
// Hauptinhalt
content: {
errorCode: '404',
title: 'Seite nicht gefunden',
description: 'Die gesuchte Seite existiert nicht oder wurde verschoben.',
},
// Aktionsbuttons
actions: {
goBack: 'Zurück',
homePage: 'Startseite'
}
};
+111
View File
@@ -0,0 +1,111 @@
// src/i18n/locales/de/pages/portfolio.ts
export const portfolio = {
// SEO und Meta-Informationen
seo: {
title: 'Portfolio - Damjan Savić',
description: 'Entdecken Sie meine Projekte im Bereich JTL-Integration, E-Commerce und Digitale Transformation.'
},
// Hauptseite
main: {
title: 'Portfolio',
loading: 'Projekte werden geladen...',
error: 'Fehler beim Laden der Projekte',
noProjects: {
title: 'Keine Projekte gefunden',
description: 'Aktuell sind keine Projekte verfügbar. Schauen Sie später wieder vorbei.'
}
},
// Projekt-Karten
projectCard: {
date: 'Datum',
technologies: 'Technologien',
moreCount: 'weitere', // für '+X weitere'
readMore: 'Mehr erfahren'
},
// Projekt-Details
project: {
navigation: {
back: 'Zurück zum Portfolio',
projectDetails: 'PROJEKT DETAILS'
},
metadata: {
date: 'Datum',
client: 'Kunde',
duration: 'Dauer',
repository: 'Repository',
documentation: 'Dokumentation',
technologies: 'Technologien',
live: 'Live-Version'
},
sections: {
overview: 'Überblick',
challenge: 'Herausforderung',
solution: 'Lösung',
results: 'Ergebnisse',
systemArchitecture: 'Systemarchitektur',
implementation: 'Implementierung',
technologies: 'Verwendete Technologien'
}
},
// Kategorien und Filter
categories: {
all: 'Alle',
'Data Science': 'Data Science',
'AI Development': 'KI-Entwicklung',
'Integration': 'Integration',
'Full-Stack Development': 'Full-Stack Entwicklung',
'Data Processing': 'Datenverarbeitung',
'Content Production': 'Content-Produktion',
'Machine Learning': 'Machine Learning',
'Automation': 'Automatisierung'
},
// Spezifische Projekte
projects: {
'ai-data-reader': {
title: 'KI-basierte Produktdatenpflege aus PDF-Dateien',
description: 'Entwicklung eines automatisierten Systems zur Extraktion und Strukturierung von Produktdaten aus PDF-Dokumenten'
},
'bi-vision': {
title: 'KI-Videos für BI-Software',
description: 'Entwicklung von KI-gestützten Erklärvideos für Business Intelligence Dashboards'
},
'business-intelligence-ai': {
title: 'KI für Business Intelligence',
description: 'Integration von KI-Modellen in Business Intelligence Systeme zur Prozessoptimierung'
},
'claude-personal-assistant': {
title: 'KI-basierter Personal Assistant mit Claude AI',
description: 'Entwicklung eines personalisierten KI-Assistenten für professionelle E-Mail-Kommunikation'
},
'e-commerce-integration': {
title: 'Integration mit TradeByte',
description: 'Integration eines Shopify-Shops mit JTL-WaWi für optimierte Bestandsführung'
},
'jtl-integration-project': {
title: 'JTL Integration Referenzprojekt',
description: 'Ein vollständiges Lagersystem in Krefeld auf Basis von JTL'
},
'local-llm-training': {
title: 'Training von lokalen KI-Modellen',
description: 'Entwicklung einer Pipeline für das Training und die Feinabstimmung lokaler KI-Modelle'
},
'processautomation': {
title: 'Automatisierung mit Python',
description: 'Entwicklung von Automatisierungslösungen für Geschäftsprozesse'
},
'rfid-automation': {
title: 'RFID-Automatisierung',
description: 'Entwicklung eines automatisierten Systems zur Erstellung und zum Druck von RFID-Etiketten'
},
'timetracking-software': {
title: 'Digitale Zeiterfassung',
description: 'Entwicklung einer modernen Zeiterfassungslösung mit Next.js, Flask und MSSQL'
}
},
// Status-Meldungen
status: {
loading: 'Wird geladen...',
error: 'Ein Fehler ist aufgetreten',
success: 'Erfolgreich geladen'
}
};
+96
View File
@@ -0,0 +1,96 @@
// src/i18n/locales/de/pages/privacy.ts
export const privacy = {
// SEO und Schema
seo: {
title: 'Datenschutzerklärung',
description: 'Datenschutzerklärung für die Portfolio-Website von Damjan Savić'
},
schema: {
name: 'Datenschutzerklärung',
description: 'Datenschutzerklärung für die Portfolio-Website von Damjan Savić'
},
// Hauptinhalt
content: {
title: 'Datenschutzerklärung',
lastUpdated: 'Zuletzt aktualisiert: 10. März 2024',
// Navigation
breadcrumbs: {
currentTitle: 'Datenschutzerklärung'
},
// Abschnitte
sections: {
introduction: {
title: '1. Einführung',
content: 'Diese Datenschutzerklärung erläutert, wie wir Ihre personenbezogenen Daten bei der Nutzung unserer Website erfassen, verwenden und schützen.'
},
dataCollection: {
title: '2. Datenerfassung',
providedInfo: {
title: '2.1 Von Ihnen bereitgestellte Informationen',
intro: 'Bei Verwendung unseres Kontaktformulars erfassen wir:',
items: [
'Name',
'E-Mail-Adresse',
'Nachrichteninhalt'
]
},
automaticInfo: {
title: '2.2 Automatisch erfasste Informationen',
intro: 'Wir erfassen automatisch:',
items: [
'IP-Adresse',
'Browser-Typ',
'Geräteinformationen',
'Besuchte Seiten',
'Verweildauer auf der Website'
]
}
},
dataUsage: {
title: '3. Verwendung Ihrer Daten',
intro: 'Wir verwenden Ihre Daten für:',
items: [
'Beantwortung Ihrer Anfragen',
'Verbesserung unserer Website',
'Analyse von Nutzungsmustern',
'Betrugsprävention'
]
},
cookies: {
title: '4. Cookies',
intro: 'Wir verwenden Cookies für:',
items: [
'Speicherung Ihrer Präferenzen',
'Analyse des Website-Verkehrs',
'Verständnis des Nutzerverhaltens'
]
},
security: {
title: '5. Datensicherheit',
intro: 'Wir implementieren geeignete Sicherheitsmaßnahmen zum Schutz Ihrer personenbezogenen Daten, einschließlich:',
items: [
'Verschlüsselung der Datenübertragung',
'Regelmäßige Sicherheitsbewertungen',
'Zugriffskontrollen',
'Sichere Datenspeicherung'
]
},
rights: {
title: '6. Ihre Rechte',
intro: 'Sie haben das Recht auf:',
items: [
'Zugriff auf Ihre personenbezogenen Daten',
'Berichtigung der Daten',
'Löschung der Daten',
'Widerspruch gegen die Datenverarbeitung',
'Datenübertragbarkeit'
]
},
contact: {
title: '7. Kontaktinformationen',
intro: 'Für datenschutzbezogene Anfragen kontaktieren Sie uns unter:',
email: 'E-Mail: privacy@damjan-savic.com'
}
}
}
};
+59
View File
@@ -0,0 +1,59 @@
// src/i18n/locales/de/pages/terms.ts
export const terms = {
// SEO und Schema
seo: {
title: 'Allgemeine Geschäftsbedingungen',
description: 'Allgemeine Geschäftsbedingungen für die Portfolio-Website von Damjan Savić'
},
schema: {
name: 'Allgemeine Geschäftsbedingungen',
description: 'Allgemeine Geschäftsbedingungen für die Portfolio-Website von Damjan Savić'
},
// Hauptinhalt
content: {
title: 'Allgemeine Geschäftsbedingungen',
lastUpdated: 'Zuletzt aktualisiert: 10. März 2024',
// Navigation
breadcrumbs: {
currentTitle: 'Allgemeine Geschäftsbedingungen'
},
// Abschnitte
sections: {
agreement: {
title: '1. Zustimmung zu den Bedingungen',
content: 'Mit dem Zugriff auf unsere Website stimmen Sie zu, an diese Allgemeinen Geschäftsbedingungen gebunden zu sein und alle geltenden Gesetze und Vorschriften einzuhalten.'
},
intellectualProperty: {
title: '2. Rechte an geistigem Eigentum',
content: 'Alle Inhalte dieser Website, einschließlich, aber nicht beschränkt auf Texte, Grafiken, Logos, Bilder und Software, sind Eigentum von Damjan Savić und durch Gesetze zum Schutz geistigen Eigentums geschützt.'
},
userResponsibilities: {
title: '3. Nutzerverantwortlichkeiten',
intro: 'Bei der Nutzung unserer Website stimmen Sie zu:',
items: [
'Korrekte Informationen bereitzustellen',
'Die Website legal und ethisch zu nutzen',
'Keinen unbefugten Zugriff zu versuchen',
'Den Betrieb der Website nicht zu stören'
]
},
liability: {
title: '4. Haftungsbeschränkung',
content: 'Wir haften nicht für indirekte, zufällige, besondere, Folge- oder Strafschäden, die sich aus Ihrer Nutzung oder Unfähigkeit zur Nutzung der Website ergeben.'
},
changes: {
title: '5. Änderungen der Bedingungen',
content: 'Wir behalten uns das Recht vor, diese Bedingungen jederzeit zu ändern. Wir werden die Nutzer über wesentliche Änderungen informieren, indem wir die neuen Allgemeinen Geschäftsbedingungen auf dieser Seite veröffentlichen.'
},
governingLaw: {
title: '6. Geltendes Recht',
content: 'Diese Bedingungen unterliegen den Gesetzen der Bundesrepublik Deutschland und werden in Übereinstimmung mit diesen ausgelegt, ohne Berücksichtigung von Kollisionsnormen.'
},
contact: {
title: '7. Kontaktinformationen',
intro: 'Bei Fragen zu diesen Allgemeinen Geschäftsbedingungen kontaktieren Sie uns bitte unter:',
email: 'E-Mail: legal@damjan-savic.com'
}
}
}
};
+53
View File
@@ -0,0 +1,53 @@
// src/i18n/locales/de/portfolio/index.ts
import aiDataReader from './projects/ai-data-reader';
export const portfolio = {
// Meta-Informationen für die Portfolio-Seite
seo: {
title: 'Portfolio - Damjan Savić',
description: 'Entdecken Sie meine Projekte im Bereich JTL-Integration, E-Commerce und digitale Transformation.'
},
// Portfolio-Überschriften und Filter
sections: {
title: 'Portfolio',
subtitle: 'Ausgewählte Projekte und Referenzen',
filterTitle: 'Kategorien',
sortTitle: 'Sortierung'
},
// Filter-Optionen
filters: {
all: 'Alle',
categories: {
'Data Science': 'Data Science',
'AI Development': 'KI-Entwicklung',
'Integration': 'Integration',
'Full-Stack Development': 'Full-Stack Entwicklung',
'Data Processing': 'Datenverarbeitung',
'Content Production': 'Content-Produktion',
'Machine Learning': 'Machine Learning',
'Automation': 'Automatisierung'
}
},
// Sortier-Optionen
sort: {
date: 'Datum',
title: 'Titel',
category: 'Kategorie'
},
// UI-Texte
ui: {
loading: 'Projekte werden geladen...',
noProjects: 'Keine Projekte gefunden',
viewProject: 'Projekt ansehen',
backToPortfolio: 'Zurück zum Portfolio',
technologies: 'Technologien',
client: 'Kunde',
duration: 'Dauer',
visitWebsite: 'Website besuchen',
viewRepository: 'Repository ansehen',
viewDocumentation: 'Dokumentation'
},
// Alle Projekte
projects: {
'ai-data-reader': aiDataReader,
}
};
@@ -0,0 +1,107 @@
// src/i18n/locales/de/portfolio/projects/ai-data-reader.ts
export const aiDataReader = {
meta: {
slug: 'ai-data-reader',
title: "KI-basierte Produktdatenpflege aus PDF-Dateien",
description: "Entwicklung eines automatisierten Systems zur Extraktion und Strukturierung von Produktdaten aus PDF-Dokumenten",
excerpt: "Integration von Claude AI für die intelligente Verarbeitung von Produktinformationen und nahtlose JTL-ERP-Integration.",
date: "2024-02",
category: "Data Processing",
client: "Amazon Seller",
duration: "2 Monate",
url: "https://www.damjan-savic.com",
repository: "",
documentation: "",
published: true,
featured: true,
technologies: ["Python", "FastAPI", "Claude AI", "PyPDF", "Pydantic", "JTL-Wawi"],
tags: ["Data Extraction", "ERP", "Process Automation", "PDF Processing"]
},
content: {
intro: "Ein KI-gestütztes System zur automatisierten Extraktion von Produktdaten aus PDF-Dokumenten mit direkter Integration in JTL-Warenwirtschaftssysteme, entwickelt für maximale Effizienz in der Produktdatenpflege.",
challenge: {
title: "Die Herausforderung",
description: "Die manuelle Erfassung von Produktdaten aus PDF-Dokumenten war zeitaufwendig und fehleranfällig.",
points: [
"Große Mengen an PDF-Dokumenten mit Produktinformationen",
"Zeitintensive manuelle Dateneingabe",
"Inkonsistente Datenqualität",
"Hoher personeller Aufwand"
]
},
solution: {
title: "Unsere Lösung",
description: "Entwicklung eines KI-gestützten Systems zur automatisierten Datenextraktion",
content: "Durch den Einsatz von Claude AI und modernen Python-Technologien haben wir eine vollautomatische Lösung geschaffen, die PDF-Dokumente verarbeitet und die extrahierten Daten direkt in das JTL-Warenwirtschaftssystem integriert.",
points: [
"Automatisierte PDF-Verarbeitung",
"KI-gestützte Datenextraktion",
"Intelligente Datenvalidierung",
"Nahtlose JTL-Integration"
]
},
technical: {
title: "Technische Umsetzung",
description: "Die Lösung basiert auf einer modularen Python-Architektur mit verschiedenen Kernkomponenten:",
points: [
"Robuste PDF-Textextraktion mit PyPDF",
"KI-gestützte Datenextraktion mit Claude AI",
"Validierung durch Pydantic Models",
"JTL-ERP Integration über CSV-Export"
],
code: `class ProductData(BaseModel):
artikel_nummer: str
name: str
hersteller: str
inhaltsstoffe: List[str]
allergene: List[str]
naehrwerte: NaehrwertData
nettogewicht: str
vegan: bool
vegetarisch: bool
def _extract_with_claude(self, prompt: str) -> Dict[str, Any]:
'''Extrahiert strukturierte Daten mit Claude AI.'''
response = self.client.messages.create(
model='claude-3-sonnet-20240229',
messages=[{
'role': 'user',
'content': prompt
}]
)
return self._clean_json_string(response.content)`
},
implementation: {
title: "Implementierungsprozess",
description: "Der automatisierte Workflow wurde in mehreren Phasen implementiert:",
points: [
"PDF-Batch-Verarbeitung aus Input-Verzeichnis",
"Intelligente Texterkennung und -strukturierung",
"Mehrschichtige Validierungslogik",
"Robuste Fehlerbehandlung",
"Integration in bestehende Systeme"
]
},
results: {
title: "Ergebnisse und Auswirkungen",
description: "Die Implementierung führte zu signifikanten Verbesserungen im Geschäftsprozess:",
points: [
"90% Zeitersparnis bei der Produktdatenpflege",
"99% Genauigkeit bei der Datenextraktion",
"Eliminierung manueller Dateneingaben",
"Standardisierte Produktdatenqualität",
"Deutlich reduzierte Fehlerquote"
]
},
conclusion: "Das entwickelte System hat die Produktdatenpflege grundlegend revolutioniert. Durch die Kombination von KI-Technologie und automatisierter Datenverarbeitung wurde nicht nur die Effizienz drastisch gesteigert, sondern auch die Datenqualität erheblich verbessert. Das Projekt zeigt eindrucksvoll, wie moderne KI-Lösungen praktische Geschäftsprobleme lösen können."
}
};
// Re-export für Kompatibilität mit dem Projektimport-System
export default aiDataReader;
+175
View File
@@ -0,0 +1,175 @@
// src/i18n/locales/en/blog/index.ts
export const blog = {
meta: {
title: 'Blog - JTL Integration & Digital Solutions',
description: 'Insights and Best Practices on JTL-WaWi, E-Commerce, and Digital Transformation',
header: {
title: 'Insights & Best Practices',
subtitle: 'Insights and Best Practices on JTL-WaWi, E-Commerce, and Digital Transformation'
}
},
posts: {
'erp-integration-breuninger': {
title: 'ApparelMagic and TradeByte: Analysis of Complex Integrations',
date: '2024-02-09',
excerpt: 'Detailed analysis of an e-commerce integration between Apparel Magic and Breuninger via TradeByte',
category: 'System Integration',
tags: ['ERP', 'Apparel Magic', 'TradeByte', 'API Integration', 'Python', 'MariaDB'],
coverImage: '/images/posts/erp-integration-breuninger/cover.jpg',
content: {
intro: {
title: 'Apparel Magic meets Breuninger: A Technical Analysis of the TradeByte Integration',
description: 'The integration of e-commerce systems with established marketplaces poses unique challenges for companies. In this article, I share my experiences from a complex integration project between Apparel Magic as an ERP system and the Breuninger platform via TradeByte.'
},
background: {
title: 'Project Background',
systems: {
erp: 'Apparel Magic as an ERP system for product data and inventory management',
middleware: 'TradeByte as the middleware for the Breuninger platform'
},
challenges: {
sync: 'Bidirectional synchronization of orders',
customers: 'Automated customer creation',
delivery: 'Management of delivery notes',
inventory: 'Real-time inventory management'
}
},
tech: {
title: 'Technical Architecture',
components: {
title: 'Key Components'
},
database: {
title: 'Middleware Database',
description: 'The MariaDB database serves as the central data store for the integration:'
}
},
api: {
title: 'API Integrations',
apparel_magic: {
title: 'Apparel Magic API',
description: 'The REST API of Apparel Magic is used for customer creation and inventory management:'
},
tradebyte: {
title: 'TradeByte Integration',
description: 'The TradeByte API uses a combination of REST and XML:'
}
},
order_process: {
title: 'Order Process',
steps: {
fetch: 'Regular retrieval of new orders from TradeByte',
customers: 'Automatic customer creation in Apparel Magic',
process: 'Order processing and status update',
delivery: 'Generation and storage of delivery notes'
},
delivery_notes: {
title: 'Delivery Note Management'
}
},
challenges: {
title: 'Challenges and Solutions',
status: {
title: '1. Status Management',
description: 'A particular challenge was managing order statuses:'
},
error_handling: {
title: '2. Error Handling and Monitoring',
description: 'Robust error handling was essential for production operation:'
}
},
best_practices: {
title: 'Best Practices',
api: {
title: '1. API Communication',
items: {
retry: 'Implementation of retry mechanisms',
errors: 'Careful error handling',
logging: 'Comprehensive logging of all communications'
}
},
data: {
title: '2. Data Management',
items: {
storage: 'Central data storage in MariaDB',
transactions: 'Transactional security for critical operations',
validation: 'Regular data validation'
}
},
automation: {
title: '3. Process Automation',
items: {
customers: 'Automated customer creation',
status: 'Automatic status updates',
delivery: 'Systematic delivery note management'
}
}
},
lessons: {
title: 'Lessons Learned',
api: {
title: '1. API Design',
items: {
docs: 'Thorough API documentation is essential',
auth: 'Understanding of various authentication methods',
limits: 'Consideration of rate limits'
}
},
validation: {
title: '2. Data Validation',
items: {
rules: 'Implementation of strict validation rules',
edge_cases: 'Careful handling of edge cases',
cleanup: 'Automated data cleanup'
}
},
optimization: {
title: '3. Process Optimization',
items: {
automation: 'Continuous improvement of automation',
performance: 'Regular performance reviews',
monitoring: 'Proactive monitoring'
}
}
},
conclusion: {
title: 'Conclusion',
requirements: {
understanding: 'Deep understanding of both systems',
implementation: 'Careful implementation of API communication',
error_handling: 'Robust error handling',
monitoring: 'Continuous monitoring'
},
results: 'The developed solution successfully processes orders and enables seamless integration between the systems. In particular, automated customer creation and delivery note management have proven to be efficiency boosters.'
}
}
},
},
ui: {
readMore: 'Read More',
loading: {
posts: 'Loading blog posts...',
post: 'Loading blog post...'
},
errors: {
posts: 'Error loading blog posts',
post: 'The requested blog post does not exist or has been moved.'
},
backToBlog: 'Back to Blog',
publishedOn: 'Published on',
category: 'Category',
tags: 'Tags',
notFound: {
title: 'Post Not Found',
message: 'The requested blog post does not exist or has been moved.'
}
},
categories: {
'Integration': 'Integration',
'Entwicklung': 'Development',
'Automatisierung': 'Automation'
}
} as const;
export type BlogConfig = typeof blog;
export type BlogPost = BlogConfig['posts'][keyof BlogConfig['posts']];
@@ -0,0 +1,138 @@
// src/i18n/locales/en/blog/posts/erp-integration-breuninger.ts
export const erpIntegrationBreuninger = {
posts: {
erp_integration: {
title: "ApparelMagic and TradeByte: Analysis of Complex Integrations",
date: "2024-02-09",
excerpt: "Detailed analysis of an e-commerce integration between Apparel Magic and Breuninger via TradeByte",
category: "System Integration",
tags: ["ERP", "Apparel Magic", "TradeByte", "API Integration", "Python", "MariaDB"],
coverImage: "/images/posts/erp-integration-breuninger/cover.jpg",
intro: {
title: "Apparel Magic meets Breuninger: A Technical Analysis of the TradeByte Integration",
description: "The integration of e-commerce systems with established marketplaces presents unique challenges for companies. In this article, I share my experiences from a complex integration project between Apparel Magic as an ERP system and the Breuninger platform via TradeByte."
},
background: {
title: "Project Background",
systems: {
erp: "Apparel Magic as an ERP system for product data and inventory management",
middleware: "TradeByte as middleware for the Breuninger platform"
},
challenges: {
sync: "Bidirectional synchronization of orders",
customers: "Automated customer creation",
delivery: "Management of delivery notes",
inventory: "Real-time inventory management"
}
},
tech: {
title: "Technical Architecture",
components: {
title: "Central Components"
},
database: {
title: "Middleware Database",
description: "The MariaDB database serves as the central data store for the integration:"
}
},
api: {
title: "API Integrations",
apparel_magic: {
title: "Apparel Magic API",
description: "The REST API of Apparel Magic is used for customer creation and inventory management:"
},
tradebyte: {
title: "TradeByte Integration",
description: "The TradeByte API uses a combination of REST and XML:"
}
},
order_process: {
title: "Order Process",
steps: {
fetch: "Regular retrieval of new orders from TradeByte",
customers: "Automatic customer creation in Apparel Magic",
process: "Order processing and status update",
delivery: "Generation and storage of delivery notes"
},
delivery_notes: {
title: "Delivery Note Management"
}
},
challenges: {
title: "Challenges and Solutions",
status: {
title: "1. Status Management",
description: "A particular challenge was managing order statuses:"
},
error_handling: {
title: "2. Error Handling and Monitoring",
description: "Robust error handling was essential for production operations:"
}
},
best_practices: {
title: "Best Practices",
api: {
title: "1. API Communication",
items: {
retry: "Implementation of retry mechanisms",
errors: "Careful error handling",
logging: "Comprehensive logging of all communications"
}
},
data: {
title: "2. Data Management",
items: {
storage: "Central data storage in MariaDB",
transactions: "Transactional security for critical operations",
validation: "Regular data validation"
}
},
automation: {
title: "3. Process Automation",
items: {
customers: "Automated customer creation",
status: "Automatic status updates",
delivery: "Systematic delivery note management"
}
}
},
lessons: {
title: "Lessons Learned",
api: {
title: "1. API Design",
items: {
docs: "Thorough API documentation is essential",
auth: "Understanding of various authentication methods",
limits: "Consideration of rate limits"
}
},
validation: {
title: "2. Data Validation",
items: {
rules: "Implementation of strict validation rules",
edge_cases: "Careful handling of edge cases",
cleanup: "Automated data cleanup"
}
},
optimization: {
title: "3. Process Optimization",
items: {
automation: "Continuous improvement of automation",
performance: "Regular performance reviews",
monitoring: "Proactive monitoring"
}
}
},
conclusion: {
title: "Conclusion",
requirements: {
understanding: "Deep understanding of both systems",
implementation: "Careful implementation of the API communication",
error_handling: "Robust error handling",
monitoring: "Continuous monitoring"
},
results: "The developed solution successfully processes orders and enables seamless integration between the systems. In particular, the automated customer creation and delivery note management have proven to enhance efficiency."
}
}
}
};
@@ -0,0 +1,253 @@
// src/i18n/locales/en/blog/posts/fullstack-development-timetracking.ts
export const fullstackDevelopmentTimetracking = {
meta: {
title: 'Fullstack Development with Python and React: Architecture of our Time Tracking Solution',
date: '2024-02-09',
excerpt: 'A technical deep dive into the implementation of a modern time tracking solution',
category: 'System Architecture',
coverImage: '/images/posts/fullstack-development-timetracking/cover.jpg',
tags: ['Python', 'React', 'TypeScript', 'MSSQL', 'System Design']
},
content: {
intro: {
title: 'Fullstack Development with Python and React: Architecture of our Time Tracking Solution',
description: 'Developing a robust time tracking solution requires not only technical expertise but also a deep understanding of complex business rules and user requirements. In this article, I share our experiences in implementing a modern fullstack time tracking solution with Python and React.'
},
systemArchitecture: {
title: 'System Architecture',
frontend: {
title: 'Frontend (Next.js + TypeScript)',
description: 'The frontend architecture is based on Next.js with TypeScript and follows a component-based approach:',
code: {
types: `// types/TimeEntry.ts
interface TimeEntry {
id: number;
date: string;
checkIn: string;
checkOut: string | null;
userId: number;
status: 'complete' | 'incomplete';
}`,
component: `// components/TimeEntryForm.tsx
const TimeEntryForm: React.FC<TimeEntryFormProps> = ({ onSubmit }) => {
const [entry, setEntry] = useState<TimeEntry>({
date: new Date().toISOString().split('T')[0],
checkIn: new Date().toLocaleTimeString(),
checkOut: null,
status: 'incomplete'
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateTimeEntry(entry)) return;
try {
await onSubmit(entry);
} catch (error) {
console.error('Error submitting time entry:', error);
}
};
return (
<form onSubmit={handleSubmit} className='space-y-4'>
<DateInput
value={entry.date}
onChange={(date) => setEntry({ ...entry, date })}
/>
<TimeInput
value={entry.checkIn}
onChange={(time) => setEntry({ ...entry, checkIn: time })}
/>
{/* Additional form elements */}
</form>
);
};`
}
},
backend: {
title: 'Backend (Flask + MSSQL)',
description: 'The backend uses Flask for the API and MSSQL for data persistence:',
code: {
models: `# models/time_entry.py
class TimeEntry(db.Model):
__tablename__ = 'Stundenzettel'
id = db.Column('ID', db.Decimal, primary_key=True)
personal_id = db.Column('Personal_ID', db.Decimal)
datum = db.Column('Datum', db.Date)
kommen = db.Column('Kommen', db.Time)
gehen = db.Column('Gehen', db.Time)
@validates('gehen')
def validate_checkout(self, key, value):
if value and value < self.kommen:
raise ValueError('Checkout time cannot be before checkin time')
return value`,
routes: `# routes/time_entries.py
@app.route('/api/time-entries', methods=['POST'])
@jwt_required
def create_time_entry():
data = request.get_json()
user_id = get_jwt_identity()
try:
validate_time_entry_creation(data, user_id)
entry = TimeEntry(
personal_id=user_id,
datum=data['date'],
kommen=data['checkIn'],
gehen=data.get('checkOut')
)
db.session.add(entry)
db.session.commit()
return jsonify(entry.to_dict()), 201
except ValidationError as e:
return jsonify({'error': str(e)}), 400`
}
}
},
businessLogic: {
title: 'Business Logic Implementation',
validation: {
title: 'Time Entry Validation',
description: 'The validation logic ensures that all business rules are followed:',
code: `def validate_time_entry_creation(data: dict, user_id: int) -> None:
'''Validates a new time entry according to business rules.'''
# Check for existing incomplete entries
incomplete_entry = TimeEntry.query.filter_by(
personal_id=user_id,
gehen=None,
datum=data['date']
).first()
if incomplete_entry:
raise ValidationError('Cannot create new entry while incomplete entry exists')
# Check for time overlap with existing entries
overlapping_entry = TimeEntry.query.filter(
TimeEntry.personal_id == user_id,
TimeEntry.datum == data['date'],
TimeEntry.kommen <= data['checkIn'],
TimeEntry.gehen >= data['checkIn']
).first()
if overlapping_entry:
raise ValidationError('Time entry overlaps with existing entry')`
}
},
databaseDesign: {
title: 'Database Design',
description: 'The MSSQL database schema is designed for efficiency and integrity:',
code: `CREATE TABLE dbo.Stundenzettel (
ID decimal NOT NULL PRIMARY KEY,
Personal_ID decimal,
Datum date,
Kommen time,
Gehen time,
xStatus int,
xBenutzer nvarchar(15),
xDatum datetime,
xVersion timestamp
);
CREATE INDEX idx_personal_datum
ON dbo.Stundenzettel(Personal_ID, Datum);`
},
security: {
title: 'Security Implementation',
authentication: {
title: 'JWT Authentication',
code: `# auth/jwt_handler.py
from flask_jwt_extended import create_access_token
def authenticate_user(username: str, password: str) -> str:
user = Personal.query.filter_by(
Benutzername=username,
Passwort=password # In production, use proper password hashing
).first()
if not user:
raise AuthenticationError('Invalid credentials')
return create_access_token(identity=user.ID)`
}
},
bestPractices: {
title: 'Best Practices and Learnings',
points: [
{
title: 'Data Validation at Multiple Levels',
items: [
'Frontend validation for immediate feedback',
'Backend validation for business rules',
'Database constraints for data integrity'
]
},
{
title: 'Error Handling',
items: [
'Structured error messages',
'User-friendly error messages in frontend',
'Detailed logging in backend'
]
},
{
title: 'Performance Optimization',
items: [
'Indexing of critical database fields',
'Frontend caching of time entries',
'Lazy loading for historical data'
]
}
]
},
challenges: {
title: 'Challenges and Solutions',
timezones: {
title: '1. Timezone Handling',
description: 'A particular challenge was the correct handling of timezones:',
code: `// utils/dateTime.ts
export const formatTimeForDisplay = (time: string): string => {
return new Date(\`1970-01-01T\${time}\`).toLocaleTimeString('de-DE', {
hour: '2-digit',
minute: '2-digit'
});
};
export const formatTimeForAPI = (time: string): string => {
return new Date(\`1970-01-01T\${time}\`).toISOString().split('T')[1];
};`
},
concurrency: {
title: '2. Concurrent Updates',
description: 'Handling concurrent updates required special attention:',
code: `from sqlalchemy import and_, or_
def update_time_entry(entry_id: int, data: dict) -> TimeEntry:
entry = TimeEntry.query.filter_by(id=entry_id).with_for_update().first()
if not entry:
raise NotFoundError('Time entry not found')
# Optimistic locking using version field
if entry.xVersion != data['version']:
raise ConcurrencyError('Entry was modified by another user')
entry.gehen = data.get('checkOut')
db.session.commit()
return entry`
},
offline: {
title: '3. Offline Capability',
description: 'For offline functionality, we implemented a service worker strategy:',
code: `// service-worker.ts
const CACHE_NAME = 'timetracking-v1';
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(response => {
return caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});`
}
},
conclusion: {
title: 'Conclusion',
description: 'Developing a time tracking solution requires careful planning and consideration of numerous business rules. By using modern technologies like Next.js, TypeScript, and Flask, we were able to implement a robust and user-friendly solution.',
keyPoints: [
'Strict typing with TypeScript',
'Comprehensive validation logic',
'Efficient database design',
'User-friendly error handling'
],
results: 'The solution has been successfully in use for several months and reliably processes hundreds of time entries daily.'
}
}
};
@@ -0,0 +1,204 @@
// src/i18n/locales/en/blog/posts/rfid-automation.ts
export const rfidAutomation = {
meta: {
title: 'RFID Label Automation: From Database to Printer',
date: '2024-02-09',
excerpt: 'A detailed technical analysis of implementing an automated RFID label printing system with Python',
category: 'System Integration',
coverImage: '/images/posts/rfid-automation/cover.jpg',
tags: ['RFID', 'Python', 'ZPL', 'Automation', 'Zebra Printer', 'EPC']
},
content: {
intro: {
title: 'RFID Label Automation: From Database to Printer',
description: 'In modern logistics and retail environments, efficient and error-free labeling of products with RFID tags is crucial. In this article, I share my experiences implementing an automated solution for generating and printing RFID labels with chip encoding.'
},
requirements: {
title: 'Project Background',
points: [
'Automatic generation of EPC codes (Electronic Product Code)',
'Creation of ZPL code for Zebra printers',
'Direct network communication with the printer',
'Integration with existing product data',
'Error handling and logging'
]
},
implementation: {
title: 'Technical Implementation',
epcGeneration: {
title: 'EPC Code Generation',
description: 'The EPC codes are generated according to the SGTIN standard (Serialized Global Trade Item Number):',
code: `def generate_encoded_epc(company_prefix, indicator, item_ref, serial):
sgtin = SGTIN(company_prefix, indicator, item_ref, serial)
return sgtin.encode()`
},
zplTemplates: {
title: 'ZPL Template Management',
description: 'ZPL templates were implemented for different label types:',
code: `def generate_zpl_code(artikelnr, description, ean, price, material, water_resistance, glass_type, encoded_epc):
formatted_price = f'{price:.2f}'
return f'''
CT~~CD,~CC^~CT~
^XA
~TA000
~JSN
^LT35
^MNW
^MTT
^PON
^PMN
^LH0,0
^JMA
^PR2,2
~SD23
^JUS
^LRN
^CI27
^PA0,1,1,0
^RS8,,,3
^XZ
^XA
^MMT
^PW413
^LL531
^LS-24
^FT150,57^A0N,33,33^FH\\^CI27^FD{artikelnr}^FS^CI27
^FT44,86^A0N,21,20^FH\\^CI27^FD{description}^FS^CI27
^FT130,141^A0N,50,51^FH\\^CI27^FD{formatted_price} €^FS^CI27
^FT167,175^A0N,21,20^FH\\^CI27^FD{material}^FS^CI27
^FT185,201^A0N,21,20^FH\\^CI27^FD{water_resistance}^FS^CI27
^FT155,227^A0N,21,20^FH\\^CI27^FD{glass_type}^FS^CI27
^BY3,2,113^FT73,420^BEN,,Y,N
^FH\\^FD{ean}^FS
^RFW,H,1,2,1^FD3000^FS
^RFW,H,2,12,1^FD{encoded_epc}^FS
^PQ1,0,1,Y
^XZ'''`
},
printerCommunication: {
title: 'Network Communication with the Printer',
description: 'Communication with the Zebra printer is done via TCP/IP:',
code: `def send_to_printer(data, printer_ip='192.168.68.50', printer_port=9100):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((printer_ip, printer_port))
sock.sendall(data.encode('utf-8'))
logger.info('Data successfully sent to printer')
except Exception as e:
logger.error(f'Error sending data to printer: {e}')`
},
serialNumberManagement: {
title: 'Data Processing and Serial Number Management',
description: 'Managing serial numbers is critical for the uniqueness of EPC codes:',
code: `def initialize_serial_number():
global current_serial_number
try:
serial_log_content = SERIAL_NUMBER_LOG_PATH.read_text().strip()
current_serial_number = int(serial_log_content)
except (FileNotFoundError, ValueError):
current_serial_number = START_SERIAL_NUMBER
def get_next_serial_number():
global current_serial_number
current_serial_number += 1
return current_serial_number
def finalize_serial_number():
SERIAL_NUMBER_LOG_PATH.write_text(str(current_serial_number))`
}
},
features: {
title: 'Implemented Features',
errorHandling: {
title: '1. Robust Error Handling',
points: [
'Input data validation',
'Network connection verification',
'Serial number persistence',
'Detailed logging of all operations'
]
},
configurability: {
title: '2. Configurability',
points: [
'Adjustable printer IP and port',
'Customizable ZPL templates',
'Flexible EPC code generation',
'Configurable serial number ranges'
]
},
scalability: {
title: '3. Scalability',
points: [
'Batch processing of product data',
'Parallel print jobs possible',
'Efficient resource management',
'Modular code for easy extensibility'
]
}
},
bestPractices: {
title: 'Best Practices',
dataValidation: {
title: '1. Data Validation',
points: [
'Strict typing for critical data fields',
'Verification of required fields',
'Format and plausibility checks'
]
},
faultTolerance: {
title: '2. Fault Tolerance',
points: [
'Automatic retry attempts',
'Graceful degradation',
'Detailed error logs'
]
},
maintainability: {
title: '3. Maintainability',
points: [
'Modular code structure',
'Comprehensive documentation',
'Clear separation of configuration and code'
]
}
},
lessonsLearned: {
title: 'Lessons Learned',
zplSpecifics: {
title: '1. ZPL Specifics',
points: [
'Detailed knowledge of ZPL specifications necessary',
'Careful validation of generated ZPL codes',
'Regular testing with different printer models'
]
},
rfidStandards: {
title: '2. RFID Standards',
points: [
'Adherence to EPC standards critical',
'Careful management of serial numbers',
'Validation of generated EPC codes'
]
},
networkCommunication: {
title: '3. Network Communication',
points: [
'Robust error handling for network issues',
'Timeouts and retry attempts',
'Buffering of print jobs'
]
}
},
conclusion: {
title: 'Conclusion',
description: 'The implemented solution enables efficient and reliable automation of the RFID labeling process. Through the combination of EPC code generation, ZPL template management, and direct printer communication, a robust system has been created that has proven itself in practice.',
keyPoints: [
'Thorough planning of system architecture',
'Comprehensive error handling',
'Careful documentation',
'Regular testing and validation'
],
results: 'The solution has been running stably in production for several months and processes hundreds of labels daily.'
}
}
};
+99
View File
@@ -0,0 +1,99 @@
export const common = {
// SEO & Meta
siteTitle: 'Damjan Savić - Digital Solutions & JTL Integration',
siteDescription: 'Developer of custom solutions for process automation',
// Navigation
nav: {
home: 'Home',
about: 'About',
services: 'Services',
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Contact'
},
// Common Actions
actions: {
readMore: 'Read More',
viewMore: 'View More',
viewAll: 'View All',
back: 'Back',
close: 'Close',
submit: 'Submit',
loading: 'Loading...'
},
// UI Components
ui: {
published: 'Published on',
lastUpdated: 'Last updated on',
category: 'Category',
categories: 'Categories',
tag: 'Tag',
tags: 'Tags',
author: 'Author',
minuteRead: 'minute read',
tableOfContents: 'Table of Contents'
},
// Error Messages
errors: {
generic: 'An error has occurred',
notFound: 'Page not found',
loading: 'Error loading',
return: 'Return to homepage'
},
// Loading States
loading: {
content: 'Loading content',
page: 'Loading page',
processing: 'Processing'
},
// Dates
dates: {
months: {
long: [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
],
short: [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
]
},
weekdays: {
long: [
'Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'
],
short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
}
},
// Social Media
social: {
followMe: 'Follow me on',
shareOn: 'Share on',
linkedin: 'LinkedIn',
github: 'GitHub',
email: 'Email'
},
// Contact Form
contact: {
title: 'Contact',
name: 'Name',
email: 'Email',
message: 'Message',
submit: 'Send Message',
success: 'Your message has been sent successfully',
error: 'There was an error sending your message'
},
// Accessibility
a11y: {
skipToContent: 'Skip to main content',
menuOpen: 'Open menu',
menuClose: 'Close menu',
darkMode: 'Toggle dark mode',
carousel: {
next: 'Next image',
previous: 'Previous image'
}
}
} as const;
export type CommonTranslations = typeof common;
+9
View File
@@ -0,0 +1,9 @@
const cookiebanner = {
cookies: {
message: "This website uses cookies to enhance your browsing experience. The data will not be shared with third parties.",
accept: "Accept Cookies",
decline: "Decline"
}
};
export default cookiebanner;
+40
View File
@@ -0,0 +1,40 @@
// src/i18n/locales/en/footer.ts
const footer = {
sections: {
contact: {
title: "Contact",
email: "info@damjan-savic.com",
location: "Cologne, Germany",
aria: {
emailLink: "Send email",
locationText: "Location"
}
},
navigation: {
title: "Navigation",
links: {
portfolio: "Portfolio",
blog: "Blog",
about: "About",
contact: "Contact"
}
},
social: {
title: "Social Media",
aria: {
linkedin: "Visit my LinkedIn profile",
github: "Visit my GitHub profile"
}
}
},
legal: {
copyright: "All rights reserved",
links: {
privacy: "Privacy Policy",
terms: "Legal Notice"
}
}
} as const;
export default footer;
export type FooterTranslations = typeof footer;
+109
View File
@@ -0,0 +1,109 @@
// src/i18n/locales/en/index.ts
// Blog post translations
import { erpIntegrationBreuninger } from './blog/posts/erp-integration-breuninger';
import { fullstackDevelopmentTimetracking } from './blog/posts/fullstack-development-timetracking';
import { rfidAutomation as blogRfidAutomation } from './blog/posts/rfid-automation';
import { blog } from './blog';
// Page translations
import { about } from './pages/about/index';
import { contact } from './pages/contact/index';
import { dashboard } from './pages/dashboard';
import { home } from './pages/home/index';
import { login } from './pages/login';
import { notfound } from './pages/notfound';
import { portfolio as portfolioPage } from './pages/portfolio';
import { privacy } from './pages/privacy';
import { terms } from './pages/terms';
// Portfolio project translations
import { aiDataReader } from './portfolio/projects/ai-data-reader';
import { portfolio } from './portfolio';
// Common translations and configurations
import { common } from './common';
import { meta } from './meta';
import { navigation } from './navigation';
// Footer translations
import footer from './footer';
// Merging all translation objects
const translations = {
// Pages
pages: {
about,
contact,
dashboard,
home,
login,
notfound,
portfolio: portfolioPage,
privacy,
terms,
},
// Blog
blog: {
...blog,
posts: {
erpIntegrationBreuninger,
fullstackDevelopmentTimetracking,
rfidAutomation: blogRfidAutomation,
},
},
// Portfolio
portfolio: {
...portfolio,
projects: {
aiDataReader,
},
},
// Footer
footer,
// Common configurations
common: {
...common,
cookies: {
message: "This website uses cookies to enhance your browsing experience and provide personalized content. The collected data will not be shared with third parties.",
accept: "Accept Cookies",
decline: "Decline"
}
},
meta,
navigation,
} as const;
// Default export: complete translations object
export default translations;
// Type definition for translations
export type Translations = typeof translations;
// Re-exports for direct access to individual modules
export {
// Pages
about,
contact,
dashboard,
home,
login,
notfound,
portfolioPage as portfolioPageTranslations,
privacy,
terms,
// Blog
blog,
erpIntegrationBreuninger,
fullstackDevelopmentTimetracking,
blogRfidAutomation as blogRfidAutomationPost,
// Portfolio
portfolio,
aiDataReader,
// Footer
footer,
// Common
common,
meta,
navigation,
};
+93
View File
@@ -0,0 +1,93 @@
export const meta = {
site: {
name: 'Damjan Savić',
title: 'Damjan Savić - Digital Solutions & JTL Integration',
subtitle: 'Developer of custom solutions for process automation',
description: 'With a background in software development and expertise in digital transformation, I help companies optimize and automate their business processes.',
keywords: [
'JTL Integration',
'E-Commerce Solutions',
'Process Automation',
'Digital Consulting',
'ERP Systems',
'Python Development',
'System Integration',
'Digital Marketing'
].join(', ')
},
company: {
name: 'Damjan Savić',
shortName: 'Damjan Savić',
description: 'Your software development partner for fast, reliable, and cost-efficient solutions.',
address: 'Rotdornallee',
city: 'Köln',
postalCode: '50999',
country: 'Germany',
phone: '+49 175 695 0979',
email: 'info@damjan-savic.com',
website: 'www.damjan-savic.com'
},
author: {
name: 'Damjan Savić',
role: 'Consultant Digital Solutions',
company: 'Ritter Digital GmbH',
location: 'Oberhausen, Germany',
email: 'info@damjan-savic.com',
website: 'www.damjan-savic.com',
languages: [
{ code: 'en', level: 'C2', name: 'English' },
{ code: 'sr', level: 'C2', name: 'Serbian' },
{ code: 'de', level: 'C2', name: 'German' },
{ code: 'fr', level: 'B2', name: 'French' },
{ code: 'es', level: 'B2', name: 'Spanish' },
{ code: 'ru', level: 'A1', name: 'Russian' }
]
},
social: {
linkedin: 'https://www.linkedin.com/in/damjansavic/',
github: 'https://github.com/damjansavic',
email: 'info@damjan-savic.com'
},
expertise: {
areas: [
'JTL Integration & Consulting',
'Process Automation',
'E-Commerce Development',
'System Integration',
'ERP Systems',
'Digital Transformation'
],
technologies: [
'Python',
'React/Next.js',
'MariaDB',
'Docker',
'JTL-WaWi',
'Shopify',
'Shopware'
]
},
seo: {
defaultLanguage: 'en',
alternateLanguages: ['de', 'sr'],
robots: 'index, follow',
googleSiteVerification: '', // If needed
og: {
type: 'website',
locale: 'en_US',
siteName: 'Damjan Savić - Digital Solutions',
images: {
url: '/images/og-image.jpg',
width: 1200,
height: 630,
alt: 'Damjan Savić - Digital Solutions & JTL Integration'
}
},
twitter: {
card: 'summary_large_image',
site: '@damjansavic',
creator: '@damjansavic'
}
}
} as const;
export type MetaConfig = typeof meta;
+79
View File
@@ -0,0 +1,79 @@
// C:\Development\Damjan Savic\Portfolio\src\i18n\locales\en\navigation.ts
export const navigation = {
// Main navigation
main: {
home: 'Home',
about: 'About',
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Contact'
},
// Dashboard and Admin
admin: {
login: 'Login',
dashboard: 'Dashboard',
logout: 'Logout'
},
// Footer Navigation
footer: {
legal: {
privacy: 'Privacy Policy',
terms: 'Terms & Conditions',
imprint: 'Imprint'
},
sections: {
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Contact'
}
},
// Page sections
sections: {
experience: 'Experience',
skills: 'Skills',
projects: 'Projects',
about: 'About'
},
// Breadcrumbs and back navigation
navigation: {
backTo: {
home: 'Back to Home',
portfolio: 'Back to Portfolio',
blog: 'Back to Blog'
},
breadcrumbs: {
home: 'Home',
portfolio: 'Portfolio',
blog: 'Blog',
about: 'About',
contact: 'Contact'
}
},
// Mobile Navigation
mobile: {
menu: 'Menu',
close: 'Close',
open: 'Open Menu'
},
// URLs (for dynamic route generation)
urls: {
home: '/',
about: '/about',
portfolio: '/portfolio',
blog: '/blog',
contact: '/contact',
login: '/login',
dashboard: '/dashboard',
privacy: '/privacy',
terms: '/terms'
},
// Meta information for navigation
meta: {
main: 'Main Navigation',
footer: 'Footer Navigation',
social: 'Social Media Navigation',
legal: 'Legal Navigation'
}
} as const;
export type NavigationConfig = typeof navigation;
+33
View File
@@ -0,0 +1,33 @@
export const hero = {
// Navigation/Header
aboutMe: 'ABOUT ME',
// Main Section
title: 'Digital Solutions Expert',
description: 'With a background in software development and expertise in digital transformation, I help companies optimize and automate their processes through innovative solutions.',
// Expertise Areas
expertise: {
processAutomation: {
title: 'Process Automation',
description: 'Development of efficient automated workflows'
},
systemIntegration: {
title: 'System Integration',
description: 'Connection and optimization of business systems'
},
customDevelopment: {
title: 'Custom Development',
description: 'Creation of tailored software solutions'
}
},
// Languages
languages: {
english: 'English',
serbian: 'Serbian',
german: 'German',
french: 'French',
spanish: 'Spanish',
russian: 'Russian'
}
} as const;
// Type for type safety
export type HeroTranslations = typeof hero;
+24
View File
@@ -0,0 +1,24 @@
import { hero } from './hero';
import { journey } from './journey';
import { schema } from './schema';
import { skillbar } from './skillbar';
import { skillgroup } from './skillgroup';
import { skills } from './skills';
import { workflow } from './workflow';
export const about = {
hero,
journey,
schema,
skillbar,
skillgroup,
skills,
workflow
} as const;
// Typen exportieren
export type { HeroTranslations } from './hero';
export type { JourneyTranslations } from './journey';
export type { SchemaTranslations } from './schema';
export type { SkillBarTranslations } from './skillbar';
export type { SkillGroupTranslations } from './skillgroup';
export type { SkillsTranslations } from './skills';
export type { WorkflowTranslations } from './workflow';
@@ -0,0 +1,95 @@
export const journey = {
// Header
title: 'Professional Journey',
subtitle: 'From digital media to enterprise solutions',
// Education Section
education: {
title: 'Education',
degrees: {
masters: {
degree: 'M.A. Software Development',
university: 'Middlesex University, London',
period: '2020 - 2022'
},
bachelors: {
degree: 'B.A. Cross-Media Production',
university: 'Middlesex University, London',
period: '2018 - 2020'
}
}
},
// Languages Section
languages: {
title: 'Languages',
items: {
english: {
name: 'English',
level: 'C2'
},
serbian: {
name: 'Serbian',
level: 'C2'
},
german: {
name: 'German',
level: 'C2'
},
french: {
name: 'French',
level: 'B2'
},
spanish: {
name: 'Spanish',
level: 'B2'
},
russian: {
name: 'Russian',
level: 'A1'
}
}
},
// Work History
work: {
positions: [
{
period: '08/2023 - Present',
company: 'Ritter Digital GmbH',
title: 'Digital Solutions Consultant',
location: 'Oberhausen',
highlights: [
'ERP consulting and implementation (JTL WaWi)',
'Process automation & full-stack development',
'RFID technology & automation',
'Lead generation & management',
'AI-supported content management'
]
},
{
period: '02/2023 - 08/2023',
company: 'Joyce & Girls Co AG',
title: 'ERP Integration Specialist',
location: 'Köln',
highlights: [
'Complex system integration (Apparel Magic, TradeByte)',
'Server administration and automation',
'Database and API development',
'Digital marketing and campaign analysis'
]
},
{
period: '08/2022 - 01/2023',
company: 'Magnarius',
title: 'RPA Developer & E-Commerce Manager',
location: 'Bergisch Gladbach',
highlights: [
'Shopware 6 development and JTL integration',
'Google Ads automation',
'CMS management and optimization',
'SEO strategy implementation'
]
}
]
}
} as const;
// Type for type safety
export type JourneyTranslations = typeof journey;
+31
View File
@@ -0,0 +1,31 @@
export const schema = {
page: {
name: 'About Damjan Savić',
description: 'Learn more about Damjan Savić, a certified JTL expert with extensive experience in e-commerce and warehouse management solutions.'
},
person: {
jobTitle: 'JTL Integration Expert',
description: 'With extensive experience in integrating and optimizing e-commerce systems, I help companies with the digital transformation of their business processes.',
languages: {
english: 'English',
serbian: 'Serbian',
german: 'German',
french: 'French',
spanish: 'Spanish',
russian: 'Russian'
},
skills: {
python: 'Python',
googleAds: 'Google Ads',
metaAds: 'Meta Ads',
shopware: 'Shopware',
shopify: 'Shopify',
wooCommerce: 'WooCommerce',
jtlWawi: 'JTL WAWI',
serverAdmin: 'Server Administration',
airflow: 'AirFlow'
}
}
} as const;
// Type for type safety
export type SchemaTranslations = typeof schema;
@@ -0,0 +1,13 @@
export const skillbar = {
// Accessibility labels
ariaLabel: {
skillLevel: 'Skill Level',
progressBar: 'Progress Bar'
},
// Screen reader text
screenReader: {
progress: '{{level}} percent progress for {{skill}}'
}
} as const;
// Type for type safety
export type SkillBarTranslations = typeof skillbar;
@@ -0,0 +1,63 @@
export const skillgroup = {
// Categories
categories: {
development: 'Development',
ecommerce: 'E-Commerce',
marketing: 'Marketing',
automation: 'Automation',
languages: 'Programming Languages',
databases: 'Databases'
},
// Skills by category
skills: {
development: {
frontend: 'Frontend Development',
backend: 'Backend Development',
fullstack: 'Full-Stack Development',
api: 'API Development',
testing: 'Software Testing'
},
ecommerce: {
jtl: 'JTL WaWi',
shopware: 'Shopware',
shopify: 'Shopify',
woocommerce: 'WooCommerce',
magento: 'Magento'
},
marketing: {
seo: 'Search Engine Optimization',
sea: 'Search Engine Advertising',
analytics: 'Web Analytics',
googleAds: 'Google Ads',
metaAds: 'Meta Ads'
},
automation: {
rpa: 'Robotic Process Automation',
workflow: 'Workflow Automation',
cicd: 'CI/CD',
testing: 'Test Automation',
deployment: 'Deployment Automation'
},
languages: {
python: 'Python',
javascript: 'JavaScript',
typescript: 'TypeScript',
php: 'PHP',
sql: 'SQL'
},
databases: {
mysql: 'MySQL',
postgresql: 'PostgreSQL',
mongodb: 'MongoDB',
redis: 'Redis',
elasticsearch: 'Elasticsearch'
}
},
// Accessibility
ariaLabels: {
skillGroup: 'Skill Group',
skillList: 'List of skills in this category'
}
} as const;
// Type for type safety
export type SkillGroupTranslations = typeof skillgroup;
+46
View File
@@ -0,0 +1,46 @@
// en/pages/about/skills.ts
export const skills = {
title: 'Skills',
skillGroups: [
{
category: 'Development',
items: [
{ name: 'Python', level: 90 },
{ name: 'Google Ads', level: 85 },
{ name: 'Meta Ads', level: 85 }
]
},
{
category: 'E-Commerce',
items: [
{ name: 'Shopware', level: 85 },
{ name: 'Shopify', level: 85 },
{ name: 'WooCommerce', level: 85 }
]
},
{
category: 'System Administration',
items: [
{ name: 'JTL WAWI', level: 85 },
{ name: 'Server', level: 75 },
{ name: 'AirFlow', level: 60 }
]
}
],
ui: {
percentage: 'percent',
levelLabel: 'Level',
skillLevel: '{{level}}% proficiency in {{skill}}'
},
aria: {
skillGroup: 'Skill group for {{category}}',
skillBar: 'Progress bar for {{skill}}',
skillIcon: 'Icon for {{category}}',
selectSkill: 'Select skill'
},
screenReader: {
skillProgress: '{{skill}} with a level of {{level}} percent'
}
} as const;
export type SkillsTranslations = typeof skills;
@@ -0,0 +1,44 @@
export const workflow = {
// Page title
title: 'MY WORKFLOW',
description: 'Systematic approach to software development through defined steps',
// Workflow steps
steps: [
{
number: '01',
title: 'REQUIREMENTS ANALYSIS'
},
{
number: '02',
title: 'ASSESSMENT OF DEADLINES AND CONSTRAINTS'
},
{
number: '03',
title: 'DEVELOPMENT ENVIRONMENT SETUP'
},
{
number: '04',
title: 'PROGRAMMING'
},
{
number: '05',
title: 'TESTING THE RESULTS'
},
{
number: '06',
title: 'CODE SUPPORT AND SCALING'
}
],
// Aria Labels for accessibility
aria: {
workflowSection: 'Workflow Process',
stepNumber: 'Step {{number}}',
stepDescription: 'Workflow step: {{title}}'
},
// Screen Reader texts
screenReader: {
stepProgress: 'Step {{number}} of {{total}}: {{title}}'
}
} as const;
// Type for type safety
export type WorkflowTranslations = typeof workflow;
@@ -0,0 +1,41 @@
// src/i18n/locales/en/pages/contact/contactform.ts
export const contactform = {
// Form Header
title: 'Contact Me',
description: 'Have questions or want to collaborate? Send me a message.',
// Form Fields
name: {
label: 'Name',
placeholder: 'Your full name'
},
email: {
label: 'Email',
placeholder: 'your.email@example.com'
},
message: {
label: 'Message',
placeholder: 'Your message to me...'
},
// Button
submit: 'Send Message',
// Status Messages
successMessage: 'Thank you for your message! I will get back to you as soon as possible.',
errorMessage: 'Sorry, there was an error sending your message. Please try again later.',
// Error Messages
errors: {
nameRequired: 'Please enter your name',
emailRequired: 'Please enter your email address',
emailInvalid: 'Please enter a valid email address',
messageRequired: 'Please enter a message'
},
// Aria Labels
aria: {
form: 'Contact form',
submitting: 'Sending form',
successAlert: 'Success message',
errorAlert: 'Error message'
}
} as const;
// Type for type safety
export type ContactFormTranslations = typeof contactform;
@@ -0,0 +1,27 @@
// src/i18n/locales/en/pages/contact/contactinfo.ts
export const contactinfo = {
// Header
title: 'Contact Information',
description: 'You can reach me through the following channels',
// Contact Method Labels
addressLabel: 'Office Location',
phoneLabel: 'Phone',
emailLabel: 'Email',
// Contact Information
address: 'Rotdornallee, Köln',
phone: '+49 175 695 0979',
email: 'info@damjan-savic.com',
// Additional Information
availabilityNote: 'Business hours: Monday to Friday, 9:00 AM - 5:00 PM',
// Aria Labels
aria: {
contactCard: 'Contact information card',
addressLink: 'Open location in Google Maps',
phoneLink: 'Call',
emailLink: 'Send email',
externalLink: 'Opens in new tab'
}
} as const;
// Type for type safety
export type ContactInfoTranslations = typeof contactinfo;
@@ -0,0 +1,71 @@
// src/i18n/locales/en/pages/contact/index.ts
export const contact = {
breadcrumb: "CONTACT",
hero: {
title: "Let's Work Together",
subtitle: "Have a project in mind? Let's discuss how we can help you achieve your goals."
},
contactInfo: {
title: "Contact Information",
description: "You can reach me through the following channels",
address: {
label: "Office Location",
value: "Rotdornallee, Köln"
},
phone: {
label: "Phone",
value: "+49 175 695 0979"
},
email: {
label: "Email",
value: "info@damjan-savic.com"
},
availabilityNote: "Business hours: Monday to Friday, 9:00 AM - 5:00 PM",
aria: {
contactCard: "Contact information card",
addressLink: "Open location in Google Maps",
phoneLink: "Call",
emailLink: "Send email",
externalLink: "Opens in new tab"
}
},
contactForm: {
title: "Contact Me",
description: "Have questions or want to collaborate? Send me a message.",
name: {
label: "Name",
placeholder: "Your full name"
},
email: {
label: "Email",
placeholder: "your.email@example.com"
},
message: {
label: "Message",
placeholder: "Your message to me..."
},
submit: "Send Message",
successMessage: "Thank you for your message! I will get back to you as soon as possible.",
errorMessage: "Sorry, there was an error sending your message. Please try again later.",
errors: {
nameRequired: "Please enter your name",
emailRequired: "Please enter your email address",
emailInvalid: "Please enter a valid email address",
messageRequired: "Please enter a message"
},
aria: {
form: "Contact form",
submitting: "Sending form",
successAlert: "Success message",
errorAlert: "Error message"
}
}
} as const;
export type ContactTranslations = typeof contact;
export default {
pages: {
contact: contact
}
};
+76
View File
@@ -0,0 +1,76 @@
// src/i18n/locales/en/pages/dashboard.ts
export const dashboard = {
// SEO
seo: {
title: 'Analytics Dashboard',
description: 'Website Analysis Dashboard'
},
// Main headings
header: {
title: 'Analytics Dashboard',
activeUsers: 'active users'
},
// Metric cards
metrics: {
pageViews: {
title: 'Page Views',
perMinute: 'per minute'
},
uniqueVisitors: {
title: 'Unique Visitors',
currentlyActive: 'currently active'
},
conversions: {
title: 'Conversions',
rate: 'conversion rate'
},
timeOnSite: {
title: 'Avg. Time on Site',
bounceRate: 'bounce rate'
}
},
// Top pages section
topPages: {
title: 'Top Pages',
columns: {
path: 'Path',
views: 'Views',
change: 'Change'
}
},
// Event tracking section
events: {
title: 'Event Tracking',
types: {
contactForm: 'Contact Form Submission',
portfolioView: 'Portfolio View',
cvDownload: 'CV Download',
blogRead: 'Blog Read'
}
},
// Status messages
status: {
loading: 'Loading Dashboard...',
error: 'Error loading data',
notAuthenticated: 'Please sign in'
},
// Miscellaneous
misc: {
viewMore: 'View More',
refresh: 'Refresh',
period: {
today: 'Today',
yesterday: 'Yesterday',
last7Days: 'Last 7 Days',
last30Days: 'Last 30 Days',
thisMonth: 'This Month',
lastMonth: 'Last Month'
}
},
// Trends and changes
trends: {
increase: 'Increase',
decrease: 'Decrease',
noChange: 'No Change'
}
};
+9
View File
@@ -0,0 +1,9 @@
// src/i18n/locales/en/pages/home/about.ts
export const about = {
title: 'About Me',
content: 'As a digital transformation consultant, I help companies improve their processes through modern software. I develop solutions for connecting inventory management systems, programs for workflow automation, and RFID applications for better product tracking. At Ritter Digital GmbH, I work with JTL software and develop custom program solutions. Another project involved connecting Breuninger\'s systems with Apparel Magic via TB.One. My goal is to make companies more efficient through software.',
image: {
alt: 'Portrait of Damjan Savić'
}
} as const;
export type AboutTranslations = typeof about;
@@ -0,0 +1,77 @@
// src/i18n/locales/en/pages/home/experience.ts
export const experience = {
title: 'Professional Experience',
navigation: {
prev: '←',
next: '→'
},
positions: [
{
role: 'Consultant Digital Solutions & Developer',
company: 'RITTER Gesellschaft für digitale Geschäftsprozesse mbH',
period: '08/2023 - PRESENT',
highlights: [
'JTL WaWi, WMS and POS consulting & implementation',
'Python-based automation solutions',
'RFID systems and GUI development',
'AI & Business Intelligence'
]
},
{
role: 'ERP Integration Specialist & E-Commerce Developer',
company: 'Joyce & Girls',
period: '01/2023 - 08/2023',
highlights: [
'ApparelMagic & TradeByte integration',
'MariaDB middleware development',
'Windows Server administration',
'Shopify optimization'
]
},
{
role: 'RPA Developer & E-Commerce Manager',
company: 'C&S Marketing',
period: '08/2022 - 01/2023',
highlights: [
'Shopware 6 & JTL integration',
'Python automation',
'Google Ads optimization',
'CMS management'
]
},
{
role: 'E-Commerce Developer',
company: 'Brands Club GmbH',
period: '08/2021 - 07/2022',
highlights: [
'Shopify & JTL integration',
'Server administration',
'Content production',
'Marketing automation'
]
},
{
role: 'E-Commerce Developer',
company: 'Feine Uhren Eupen',
period: '01/2021 - 08/2021',
highlights: [
'Shopware 5 development',
'Product photography',
'Luxury watch segment sales',
'E-Commerce management'
]
},
{
role: 'Online Marketing Manager',
company: 'Ufer8, Ambis, Teatro & Die Halle Tor 2',
period: '01/2018 - 12/2020',
highlights: [
'Social media content',
'Event marketing',
'Event organization',
'Marketing automation'
]
}
]
} as const;
export type ExperienceTranslations = typeof experience;
@@ -0,0 +1,27 @@
// src/i18n/locales/en/pages/home/expertise.ts
export const expertise = {
title: 'Areas of Expertise',
areas: [
{
title: 'ERP Integration',
description: 'Expert in JTL-Wawi implementation, configuration, and optimization. Specialized in inventory management systems and POS integration.',
skills: ['JTL-Wawi', 'JTL-WMS', 'JTL-POS', 'Apparel Magic']
},
{
title: 'Development',
description: 'Full-stack development with focus on Python automation, React frontends, and database design.',
skills: ['Python', 'React/Next.js', 'MariaDB', 'Docker']
},
{
title: 'E-Commerce',
description: 'Extensive experience with various e-commerce platforms and marketplace integrations.',
skills: ['Shopify', 'Shopware', 'WooCommerce', 'API Integration']
},
{
title: 'Digital Marketing',
description: 'Strategic approach to digital marketing with focus on automation and analytics.',
skills: ['Google Ads', 'Meta Ads', 'SEO', 'Analytics']
}
]
} as const;
export type ExpertiseTranslations = typeof expertise;
+28
View File
@@ -0,0 +1,28 @@
// src/i18n/locales/en/pages/home/hero.ts
export const hero = {
title: 'SOFTWARE ENGINEER',
name: 'DAMJAN SAVIĆ',
cta: 'GET IN TOUCH',
image: {
alt: 'Portrait of Damjan Savić'
},
social: {
getInTouch: 'Get in touch',
linkedin: {
title: 'Visit my LinkedIn profile'
},
github: {
title: 'Visit my GitHub profile'
},
email: {
title: 'Send me an email'
}
},
navigation: {
experience: 'EXPERIENCE',
skills: 'SKILLS',
projects: 'PROJECTS',
about: 'ABOUT'
}
} as const;
export type HeroTranslations = typeof hero;
+25
View File
@@ -0,0 +1,25 @@
// src/i18n/locales/de/pages/home/index.ts
import { hero } from './hero';
import { about } from './about';
import { experience } from './experience';
import { expertise } from './expertise';
import { skills } from './skills';
import { projects } from './projects';
export const home = {
hero,
about,
experience,
expertise,
skills,
projects
} as const;
export type HomeTranslations = typeof home;
// Re-export individual sections for direct access
export {
hero,
about,
experience,
expertise,
skills,
projects
};
@@ -0,0 +1,10 @@
// src/i18n/locales/en/pages/home/projects.ts
export const projects = {
title: 'Portfolio',
viewAll: 'All Projects →',
loading: 'Loading projects...',
error: {
loading: 'Error loading projects'
}
} as const;
export type ProjectsTranslations = typeof projects;
+41
View File
@@ -0,0 +1,41 @@
// src/i18n/locales/en/pages/home/skills.ts
export const skills = {
title: 'Skills',
skills: [
{
name: 'ERP',
level: 90,
description: 'Enterprise Resource Planning'
},
{
name: 'Database',
level: 85,
description: 'Database development and administration'
},
{
name: 'E-Commerce',
level: 95,
description: 'Online commerce and platforms'
},
{
name: 'Python',
level: 80,
description: 'Python programming language'
},
{
name: 'React',
level: 75,
description: 'Frontend development with React'
},
{
name: 'Server',
level: 70,
description: 'Server administration'
}
],
aria: {
skillLevel: 'Skill level',
selectSkill: 'Select skill'
}
} as const;
export type SkillsTranslations = typeof skills;
+54
View File
@@ -0,0 +1,54 @@
// src/i18n/locales/en/pages/login.ts
export const login = {
// SEO
seo: {
title: 'Login',
description: 'Sign in to access the dashboard'
},
// Main heading
header: {
title: 'Sign in to Dashboard'
},
// Form
form: {
// Fields
email: {
label: 'Email Address',
placeholder: 'your.email@example.com'
},
password: {
label: 'Password',
placeholder: 'Your password'
},
// Buttons
submit: {
default: 'Sign In',
loading: 'Signing in...'
},
// Error messages
errors: {
default: 'An error has occurred',
invalidCredentials: 'Invalid credentials',
emailRequired: 'Please enter your email address',
passwordRequired: 'Please enter your password',
emailInvalid: 'Please enter a valid email address'
}
},
// Links and help
help: {
forgotPassword: 'Forgot Password?',
needHelp: 'Need Help?',
contactSupport: 'Contact Support'
},
// Status messages
status: {
authenticating: 'Authenticating...',
success: 'Successfully signed in',
redirecting: 'Redirecting to dashboard...'
},
// Security notices
security: {
secureConnection: 'Secure Connection',
privacyNote: 'Your data is transmitted encrypted'
}
};
+19
View File
@@ -0,0 +1,19 @@
// src/i18n/locales/en/pages/notfound.ts
export const notfound = {
// SEO
seo: {
title: '404 - Page Not Found',
description: 'The requested page does not exist.'
},
// Main content
content: {
errorCode: '404',
title: 'Page Not Found',
description: 'The page you are looking for does not exist or has been moved.',
},
// Action buttons
actions: {
goBack: 'Go Back',
homePage: 'Home Page'
}
};
+111
View File
@@ -0,0 +1,111 @@
// src/i18n/locales/en/pages/portfolio.ts
export const portfolio = {
// SEO and meta information
seo: {
title: 'Portfolio - Damjan Savić',
description: 'Discover my projects in JTL integration, e-commerce, and digital transformation.'
},
// Main page
main: {
title: 'Portfolio',
loading: 'Loading projects...',
error: 'Error loading projects',
noProjects: {
title: 'No Projects Found',
description: 'Currently, no projects are available. Please check back later.'
}
},
// Project cards
projectCard: {
date: 'Date',
technologies: 'Technologies',
moreCount: 'more', // for '+X more'
readMore: 'Learn More'
},
// Project details
project: {
navigation: {
back: 'Back to Portfolio',
projectDetails: 'PROJECT DETAILS'
},
metadata: {
date: 'Date',
client: 'Client',
duration: 'Duration',
repository: 'Repository',
documentation: 'Documentation',
technologies: 'Technologies',
live: 'Live Version'
},
sections: {
overview: 'Overview',
challenge: 'Challenge',
solution: 'Solution',
results: 'Results',
systemArchitecture: 'System Architecture',
implementation: 'Implementation',
technologies: 'Technologies Used'
}
},
// Categories and filters
categories: {
all: 'All',
'Data Science': 'Data Science',
'AI Development': 'AI Development',
'Integration': 'Integration',
'Full-Stack Development': 'Full-Stack Development',
'Data Processing': 'Data Processing',
'Content Production': 'Content Production',
'Machine Learning': 'Machine Learning',
'Automation': 'Automation'
},
// Specific projects
projects: {
'ai-data-reader': {
title: 'AI-Based Product Data Management from PDF Files',
description: 'Development of an automated system for extracting and structuring product data from PDF documents'
},
'bi-vision': {
title: 'AI Videos for BI Software',
description: 'Development of AI-powered explainer videos for business intelligence dashboards'
},
'business-intelligence-ai': {
title: 'AI for Business Intelligence',
description: 'Integration of AI models into business intelligence systems for process optimization'
},
'claude-personal-assistant': {
title: 'AI-Based Personal Assistant with Claude AI',
description: 'Development of a personalized AI assistant for professional email communication'
},
'e-commerce-integration': {
title: 'Integration with TradeByte',
description: 'Integration of a Shopify store with JTL-WaWi for optimized inventory management'
},
'jtl-integration-project': {
title: 'JTL Integration Reference Project',
description: 'A complete warehouse system in Krefeld based on JTL'
},
'local-llm-training': {
title: 'Training of Local AI Models',
description: 'Development of a pipeline for training and fine-tuning local AI models'
},
'processautomation': {
title: 'Automation with Python',
description: 'Development of automation solutions for business processes'
},
'rfid-automation': {
title: 'RFID Automation',
description: 'Development of an automated system for creating and printing RFID labels'
},
'timetracking-software': {
title: 'Digital Time Tracking',
description: 'Development of a modern time tracking solution with Next.js, Flask, and MSSQL'
}
},
// Status messages
status: {
loading: 'Loading...',
error: 'An error has occurred',
success: 'Successfully loaded'
}
};
+96
View File
@@ -0,0 +1,96 @@
// src/i18n/locales/en/pages/privacy.ts
export const privacy = {
// SEO and Schema
seo: {
title: 'Privacy Policy',
description: 'Privacy Policy for Damjan Savić\'s portfolio website'
},
schema: {
name: 'Privacy Policy',
description: 'Privacy Policy for Damjan Savić\'s portfolio website'
},
// Main content
content: {
title: 'Privacy Policy',
lastUpdated: 'Last updated: March 10, 2024',
// Navigation
breadcrumbs: {
currentTitle: 'Privacy Policy'
},
// Sections
sections: {
introduction: {
title: '1. Introduction',
content: 'This Privacy Policy explains how we collect, use, and protect your personal data when you use our website.'
},
dataCollection: {
title: '2. Data Collection',
providedInfo: {
title: '2.1 Information You Provide',
intro: 'When using our contact form, we collect:',
items: [
'Name',
'Email address',
'Message content'
]
},
automaticInfo: {
title: '2.2 Automatically Collected Information',
intro: 'We automatically collect:',
items: [
'IP address',
'Browser type',
'Device information',
'Pages visited',
'Time spent on the website'
]
}
},
dataUsage: {
title: '3. Use of Your Data',
intro: 'We use your data for:',
items: [
'Responding to your inquiries',
'Improving our website',
'Analyzing usage patterns',
'Fraud prevention'
]
},
cookies: {
title: '4. Cookies',
intro: 'We use cookies for:',
items: [
'Storing your preferences',
'Analyzing website traffic',
'Understanding user behavior'
]
},
security: {
title: '5. Data Security',
intro: 'We implement appropriate security measures to protect your personal data, including:',
items: [
'Data transmission encryption',
'Regular security assessments',
'Access controls',
'Secure data storage'
]
},
rights: {
title: '6. Your Rights',
intro: 'You have the right to:',
items: [
'Access your personal data',
'Rectify the data',
'Delete the data',
'Object to data processing',
'Data portability'
]
},
contact: {
title: '7. Contact Information',
intro: 'For privacy-related inquiries, contact us at:',
email: 'Email: privacy@damjan-savic.com'
}
}
}
};
+59
View File
@@ -0,0 +1,59 @@
// src/i18n/locales/en/pages/terms.ts
export const terms = {
// SEO and Schema
seo: {
title: 'Terms and Conditions',
description: 'Terms and Conditions for Damjan Savić\'s portfolio website'
},
schema: {
name: 'Terms and Conditions',
description: 'Terms and Conditions for Damjan Savić\'s portfolio website'
},
// Main content
content: {
title: 'Terms and Conditions',
lastUpdated: 'Last updated: March 10, 2024',
// Navigation
breadcrumbs: {
currentTitle: 'Terms and Conditions'
},
// Sections
sections: {
agreement: {
title: '1. Agreement to Terms',
content: 'By accessing our website, you agree to be bound by these Terms and Conditions and to comply with all applicable laws and regulations.'
},
intellectualProperty: {
title: '2. Intellectual Property Rights',
content: 'All content on this website, including but not limited to text, graphics, logos, images, and software, is the property of Damjan Savić and is protected by intellectual property laws.'
},
userResponsibilities: {
title: '3. User Responsibilities',
intro: 'When using our website, you agree to:',
items: [
'Provide accurate information',
'Use the website legally and ethically',
'Not attempt unauthorized access',
'Not disrupt the website\'s operation'
]
},
liability: {
title: '4. Limitation of Liability',
content: 'We are not liable for any indirect, incidental, special, consequential, or punitive damages resulting from your use or inability to use the website.'
},
changes: {
title: '5. Changes to Terms',
content: 'We reserve the right to modify these terms at any time. We will notify users of any material changes by posting the new Terms and Conditions on this page.'
},
governingLaw: {
title: '6. Governing Law',
content: 'These terms are governed by and construed in accordance with the laws of the Federal Republic of Germany, without regard to its conflict of law provisions.'
},
contact: {
title: '7. Contact Information',
intro: 'For questions about these Terms and Conditions, please contact us at:',
email: 'Email: legal@damjan-savic.com'
}
}
}
};
+53
View File
@@ -0,0 +1,53 @@
// src/i18n/locales/en/portfolio/index.ts
import { aiDataReader } from './projects/ai-data-reader';
export const portfolio = {
// Meta information for the portfolio page
seo: {
title: 'Portfolio - Damjan Savić',
description: 'Discover my projects in JTL integration, e-commerce, and digital transformation.'
},
// Portfolio headings and filters
sections: {
title: 'Portfolio',
subtitle: 'Selected projects and references',
filterTitle: 'Categories',
sortTitle: 'Sort'
},
// Filter options
filters: {
all: 'All',
categories: {
'Data Science': 'Data Science',
'AI Development': 'AI Development',
'Integration': 'Integration',
'Full-Stack Development': 'Full-Stack Development',
'Data Processing': 'Data Processing',
'Content Production': 'Content Production',
'Machine Learning': 'Machine Learning',
'Automation': 'Automation'
}
},
// Sort options
sort: {
date: 'Date',
title: 'Title',
category: 'Category'
},
// UI texts
ui: {
loading: 'Loading projects...',
noProjects: 'No projects found',
viewProject: 'View project',
backToPortfolio: 'Back to portfolio',
technologies: 'Technologies',
client: 'Client',
duration: 'Duration',
visitWebsite: 'Visit website',
viewRepository: 'View repository',
viewDocumentation: 'Documentation'
},
// All projects
projects: {
'ai-data-reader': aiDataReader,
}
};
@@ -0,0 +1,107 @@
// src/i18n/locales/en/portfolio/projects/ai-data-reader.ts
export const aiDataReader = {
meta: {
slug: 'ai-data-reader',
title: "AI-Based Product Data Management from PDF Files",
description: "Development of an automated system for extracting and structuring product data from PDF documents",
excerpt: "Integration of Claude AI for intelligent processing of product information and seamless JTL ERP integration.",
date: "2024-02",
category: "Data Processing",
client: "Amazon Seller",
duration: "2 months",
url: "https://www.damjan-savic.com",
repository: "",
documentation: "",
published: true,
featured: true,
technologies: ["Python", "FastAPI", "Claude AI", "PyPDF", "Pydantic", "JTL-Wawi"],
tags: ["Data Extraction", "ERP", "Process Automation", "PDF Processing"]
},
content: {
intro: "An AI-powered system for automated extraction of product data from PDF documents with direct integration into JTL inventory management systems, developed for maximum efficiency in product data management.",
challenge: {
title: "The Challenge",
description: "Manual processing of product data from PDF documents was time-consuming and error-prone.",
points: [
"Large volumes of PDF documents containing product information",
"Time-intensive manual data entry",
"Inconsistent data quality",
"High personnel requirements"
]
},
solution: {
title: "Our Solution",
description: "Development of an AI-powered system for automated data extraction",
content: "By leveraging Claude AI and modern Python technologies, we created a fully automated solution that processes PDF documents and integrates the extracted data directly into the JTL inventory management system.",
points: [
"Automated PDF processing",
"AI-powered data extraction",
"Intelligent data validation",
"Seamless JTL integration"
]
},
technical: {
title: "Technical Implementation",
description: "The solution is based on a modular Python architecture with several core components:",
points: [
"Robust PDF text extraction with PyPDF",
"AI-powered data extraction with Claude AI",
"Validation through Pydantic Models",
"JTL ERP integration via CSV export"
],
code: `class ProductData(BaseModel):
artikel_nummer: str
name: str
hersteller: str
inhaltsstoffe: List[str]
allergene: List[str]
naehrwerte: NaehrwertData
nettogewicht: str
vegan: bool
vegetarisch: bool
def _extract_with_claude(self, prompt: str) -> Dict[str, Any]:
'''Extracts structured data with Claude AI.'''
response = self.client.messages.create(
model='claude-3-sonnet-20240229',
messages=[{
'role': 'user',
'content': prompt
}]
)
return self._clean_json_string(response.content)`
},
implementation: {
title: "Implementation Process",
description: "The automated workflow was implemented in several phases:",
points: [
"PDF batch processing from input directory",
"Intelligent text recognition and structuring",
"Multi-layer validation logic",
"Robust error handling",
"Integration with existing systems"
]
},
results: {
title: "Results and Impact",
description: "The implementation led to significant improvements in business processes:",
points: [
"90% time savings in product data management",
"99% accuracy in data extraction",
"Elimination of manual data entry",
"Standardized product data quality",
"Significantly reduced error rate"
]
},
conclusion: "The developed system has revolutionized product data management. By combining AI technology with automated data processing, we not only drastically increased efficiency but also significantly improved data quality. The project demonstrates impressively how modern AI solutions can solve practical business problems."
}
};
// Re-export for compatibility with the project import system
export default aiDataReader;
+175
View File
@@ -0,0 +1,175 @@
// src/i18n/locales/sr/blog/index.ts
export const blog = {
meta: {
title: 'Blog - JTL Integracija i Digitalna Rešenja',
description: 'Uvidi i najbolje prakse o JTL-WaWi, e-trgovini i digitalnoj transformaciji',
header: {
title: 'Uvidi i Najbolje Prakse',
subtitle: 'Uvidi i najbolje prakse o JTL-WaWi, e-trgovini i digitalnoj transformaciji'
}
},
posts: {
'erp-integration-breuninger': {
title: 'ApparelMagic i TradeByte: Analiza složenih integracija',
date: '2024-02-09',
excerpt: 'Detaljna analiza e-trgovinske integracije između Apparel Magic i Breuninger preko TradeByte',
category: 'Sistemska integracija',
tags: ['ERP', 'Apparel Magic', 'TradeByte', 'API Integration', 'Python', 'MariaDB'],
coverImage: '/images/posts/erp-integration-breuninger/cover.jpg',
content: {
intro: {
title: 'Apparel Magic susreće Breuninger: Tehnička analiza TradeByte integracije',
description: 'Integracija e-trgovinskih sistema sa uspostavljenim tržištima predstavlja poseban izazov za kompanije. U ovom članku delim svoje iskustvo iz složenog integracionog projekta između Apparel Magic kao ERP sistema i Breuninger platforme preko TradeByte.'
},
background: {
title: 'Pozadina projekta',
systems: {
erp: 'Apparel Magic kao ERP sistem za podatke o proizvodima i upravljanje zalihama',
middleware: 'TradeByte kao middleware za Breuninger platformu'
},
challenges: {
sync: 'Dvosmerna sinhronizacija porudžbina',
customers: 'Automatsko kreiranje kupaca',
delivery: 'Upravljanje otpremnicama',
inventory: 'Upravljanje zalihama u realnom vremenu'
}
},
tech: {
title: 'Tehnička arhitektura',
components: {
title: 'Centralne komponente'
},
database: {
title: 'Middleware baza podataka',
description: 'MariaDB baza podataka služi kao centralno skladište podataka za integraciju:'
}
},
api: {
title: 'API integracije',
apparel_magic: {
title: 'Apparel Magic API',
description: 'REST API kompanije Apparel Magic se koristi za kreiranje kupaca i upravljanje zalihama:'
},
tradebyte: {
title: 'TradeByte integracija',
description: 'TradeByte API koristi kombinaciju REST i XML:'
}
},
order_process: {
title: 'Proces porudžbine',
steps: {
fetch: 'Redovno preuzimanje novih porudžbina sa TradeByte',
customers: 'Automatsko kreiranje kupaca u Apparel Magic',
process: 'Obrada porudžbina i ažuriranje statusa',
delivery: 'Generisanje i čuvanje otpremnica'
},
delivery_notes: {
title: 'Upravljanje otpremnicama'
}
},
challenges: {
title: 'Izazovi i rešenja',
status: {
title: '1. Upravljanje statusom',
description: 'Poseban izazov je bio upravljanje statusima porudžbina:'
},
error_handling: {
title: '2. Rukovanje greškama i nadzor',
description: 'Robusno rukovanje greškama bilo je ključno za rad u produkciji:'
}
},
best_practices: {
title: 'Najbolje prakse',
api: {
title: '1. API komunikacija',
items: {
retry: 'Implementacija mehanizama ponovnog pokušaja',
errors: 'Pažljivo rukovanje greškama',
logging: 'Detaljno logovanje svih komunikacija'
}
},
data: {
title: '2. Upravljanje podacima',
items: {
storage: 'Centralno čuvanje podataka u MariaDB',
transactions: 'Sigurnost transakcija pri kritičnim operacijama',
validation: 'Redovna validacija podataka'
}
},
automation: {
title: '3. Automatizacija procesa',
items: {
customers: 'Automatsko kreiranje kupaca',
status: 'Automatsko ažuriranje statusa',
delivery: 'Sistematsko upravljanje otpremnicama'
}
}
},
lessons: {
title: 'Naučene lekcije',
api: {
title: '1. Dizajn API-ja',
items: {
docs: 'Temeljna API dokumentacija je neophodna',
auth: 'Razumevanje različitih metoda autentifikacije',
limits: 'Uzimanje u obzir ograničenja brzine'
}
},
validation: {
title: '2. Validacija podataka',
items: {
rules: 'Implementacija strogih pravila validacije',
edge_cases: 'Pažljivo rukovanje specijalnim slučajevima',
cleanup: 'Automatsko čišćenje podataka'
}
},
optimization: {
title: '3. Optimizacija procesa',
items: {
automation: 'Kontinuirano unapređenje automatizacije',
performance: 'Redovni pregledi performansi',
monitoring: 'Proaktivni nadzor'
}
}
},
conclusion: {
title: 'Zaključak',
requirements: {
understanding: 'Duboko razumevanje oba sistema',
implementation: 'Pažljiva implementacija API komunikacije',
error_handling: 'Robusno rukovanje greškama',
monitoring: 'Kontinuirani nadzor'
},
results: 'Razvijeno rešenje uspešno obrađuje porudžbine i omogućava besprekornu integraciju između sistema. Posebno se automatizovano kreiranje kupaca i upravljanje otpremnicama pokazali kao povećavači efikasnosti.'
}
}
},
},
ui: {
readMore: 'Pročitaj više',
loading: {
posts: 'Učitavaju se blog postovi...',
post: 'Učitava se blog post...'
},
errors: {
posts: 'Greška pri učitavanju blog postova',
post: 'Traženi blog post ne postoji ili je premješten.'
},
backToBlog: 'Nazad na blog',
publishedOn: 'Objavljeno dana',
category: 'Kategorija',
tags: 'Oznake',
notFound: {
title: 'Post nije pronađen',
message: 'Traženi blog post ne postoji ili je premješten.'
}
},
categories: {
'Integration': 'Integracija',
'Entwicklung': 'Razvoj',
'Automatisierung': 'Automatizacija'
}
} as const;
export type BlogConfig = typeof blog;
export type BlogPost = BlogConfig['posts'][keyof BlogConfig['posts']];
@@ -0,0 +1,138 @@
// src/i18n/locales/sr/blog/posts/erp-integration-breuninger.ts
export const erpIntegrationBreuninger = {
posts: {
erp_integration: {
title: 'ApparelMagic i TradeByte: Analiza kompleksnih integracija',
date: '2024-02-09',
excerpt: 'Detaljna analiza e-commerce integracije između Apparel Magic-a i Breuninger-a preko TradeByte-a',
category: 'Sistemska integracija',
tags: ['ERP', 'Apparel Magic', 'TradeByte', 'API integracija', 'Python', 'MariaDB'],
coverImage: '/images/posts/erp-integration-breuninger/cover.jpg',
intro: {
title: 'Apparel Magic susreće Breuninger: Tehnička analiza TradeByte integracije',
description: 'Integracija e-commerce sistema sa etabliranim marketplace-ima predstavlja poseban izazov za kompanije. U ovom članku delim svoja iskustva iz kompleksnog integracionog projekta između Apparel Magic-a kao ERP sistema i Breuninger platforme preko TradeByte-a.'
},
background: {
title: 'Pozadina projekta',
systems: {
erp: 'Apparel Magic kao ERP sistem za podatke o proizvodima i upravljanje zalihama',
middleware: 'TradeByte kao middleware za Breuninger platformu'
},
challenges: {
sync: 'Bidirekciona sinhronizacija porudžbina',
customers: 'Automatsko kreiranje kupaca',
delivery: 'Upravljanje otpremnicama',
inventory: 'Upravljanje zalihama u realnom vremenu'
}
},
tech: {
title: 'Tehnička arhitektura',
components: {
title: 'Centralne komponente'
},
database: {
title: 'Middleware baza podataka',
description: 'MariaDB baza podataka služi kao centralno skladište podataka za integraciju:'
}
},
api: {
title: 'API integracije',
apparel_magic: {
title: 'Apparel Magic API',
description: 'REST API Apparel Magic-a se koristi za kreiranje kupaca i upravljanje zalihama:'
},
tradebyte: {
title: 'TradeByte integracija',
description: 'TradeByte API koristi kombinaciju REST-a i XML-a:'
}
},
order_process: {
title: 'Proces poručivanja',
steps: {
fetch: 'Redovno preuzimanje novih porudžbina sa TradeByte-a',
customers: 'Automatsko kreiranje kupaca u Apparel Magic-u',
process: 'Obrada porudžbina i ažuriranje statusa',
delivery: 'Generisanje i čuvanje otpremnica'
},
delivery_notes: {
title: 'Upravljanje otpremnicama'
}
},
challenges: {
title: 'Izazovi i rešenja',
status: {
title: '1. Upravljanje statusima',
description: 'Poseban izazov je bilo upravljanje statusima porudžbina:'
},
error_handling: {
title: '2. Obrada grešaka i monitoring',
description: 'Robusna obrada grešaka je bila ključna za rad u produkciji:'
}
},
best_practices: {
title: 'Najbolje prakse',
api: {
title: '1. API komunikacija',
items: {
retry: 'Implementacija retry mehanizama',
errors: 'Pažljivo rukovanje greškama',
logging: 'Detaljno logovanje sve komunikacije'
}
},
data: {
title: '2. Upravljanje podacima',
items: {
storage: 'Centralno skladištenje podataka u MariaDB',
transactions: 'Transakciona sigurnost kod kritičnih operacija',
validation: 'Redovna validacija podataka'
}
},
automation: {
title: '3. Automatizacija procesa',
items: {
customers: 'Automatizovano kreiranje kupaca',
status: 'Automatsko ažuriranje statusa',
delivery: 'Sistematsko upravljanje otpremnicama'
}
}
},
lessons: {
title: 'Naučene lekcije',
api: {
title: '1. API dizajn',
items: {
docs: 'Temeljna API dokumentacija je ključna',
auth: 'Razumevanje različitih metoda autentifikacije',
limits: 'Uzimanje u obzir rate limit-a'
}
},
validation: {
title: '2. Validacija podataka',
items: {
rules: 'Implementacija strogih pravila validacije',
edge_cases: 'Pažljivo rukovanje posebnim slučajevima',
cleanup: 'Automatsko čišćenje podataka'
}
},
optimization: {
title: '3. Optimizacija procesa',
items: {
automation: 'Kontinuirano poboljšanje automatizacije',
performance: 'Redovne provere performansi',
monitoring: 'Proaktivni monitoring'
}
}
},
conclusion: {
title: 'Zaključak',
requirements: {
understanding: 'Duboko razumevanje oba sistema',
implementation: 'Pažljiva implementacija API komunikacije',
error_handling: 'Robusna obrada grešaka',
monitoring: 'Kontinuirani monitoring'
},
results: 'Razvijeno rešenje uspešno obrađuje porudžbine i omogućava besprekornu integraciju između sistema. Posebno su se automatizovano kreiranje kupaca i upravljanje otpremnicama pokazali kao faktori koji povećavaju efikasnost.'
}
}
}
};
@@ -0,0 +1,253 @@
// src/i18n/locales/sr/blog/posts/fullstack-development-timetracking.ts
export const fullstackDevelopmentTimetracking = {
meta: {
title: 'Fullstack razvoj sa Python-om i React-om: Arhitektura našeg rešenja za evidenciju radnog vremena',
date: '2024-02-09',
excerpt: 'Tehnički dubinski uvid u implementaciju modernog rešenja za evidenciju radnog vremena',
category: 'Sistemska arhitektura',
coverImage: '/images/posts/fullstack-development-timetracking/cover.jpg',
tags: ['Python', 'React', 'TypeScript', 'MSSQL', 'System Design']
},
content: {
intro: {
title: 'Fullstack razvoj sa Python-om i React-om: Arhitektura našeg rešenja za evidenciju radnog vremena',
description: 'Razvoj robusnog rešenja za evidenciju radnog vremena zahteva ne samo tehničko znanje, već i duboko razumevanje kompleksnih poslovnih pravila i korisničkih zahteva. U ovom članku delim naša iskustva u implementaciji modernog fullstack rešenja za evidenciju radnog vremena sa Python-om i React-om.'
},
systemArchitecture: {
title: 'Sistemska arhitektura',
frontend: {
title: 'Frontend (Next.js + TypeScript)',
description: 'Frontend arhitektura je bazirana na Next.js-u sa TypeScript-om i prati komponentni pristup:',
code: {
types: `// types/TimeEntry.ts
interface TimeEntry {
id: number;
date: string;
checkIn: string;
checkOut: string | null;
userId: number;
status: 'complete' | 'incomplete';
}`,
component: `// components/TimeEntryForm.tsx
const TimeEntryForm: React.FC<TimeEntryFormProps> = ({ onSubmit }) => {
const [entry, setEntry] = useState<TimeEntry>({
date: new Date().toISOString().split('T')[0],
checkIn: new Date().toLocaleTimeString(),
checkOut: null,
status: 'incomplete'
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateTimeEntry(entry)) return;
try {
await onSubmit(entry);
} catch (error) {
console.error('Error submitting time entry:', error);
}
};
return (
<form onSubmit={handleSubmit} className='space-y-4'>
<DateInput
value={entry.date}
onChange={(date) => setEntry({ ...entry, date })}
/>
<TimeInput
value={entry.checkIn}
onChange={(time) => setEntry({ ...entry, checkIn: time })}
/>
{/* Additional form elements */}
</form>
);
};`
}
},
backend: {
title: 'Backend (Flask + MSSQL)',
description: 'Backend koristi Flask za API i MSSQL za perzistenciju podataka:',
code: {
models: `# models/time_entry.py
class TimeEntry(db.Model):
__tablename__ = 'Stundenzettel'
id = db.Column('ID', db.Decimal, primary_key=True)
personal_id = db.Column('Personal_ID', db.Decimal)
datum = db.Column('Datum', db.Date)
kommen = db.Column('Kommen', db.Time)
gehen = db.Column('Gehen', db.Time)
@validates('gehen')
def validate_checkout(self, key, value):
if value and value < self.kommen:
raise ValueError('Checkout time cannot be before checkin time')
return value`,
routes: `# routes/time_entries.py
@app.route('/api/time-entries', methods=['POST'])
@jwt_required
def create_time_entry():
data = request.get_json()
user_id = get_jwt_identity()
try:
validate_time_entry_creation(data, user_id)
entry = TimeEntry(
personal_id=user_id,
datum=data['date'],
kommen=data['checkIn'],
gehen=data.get('checkOut')
)
db.session.add(entry)
db.session.commit()
return jsonify(entry.to_dict()), 201
except ValidationError as e:
return jsonify({'error': str(e)}), 400`
}
}
},
businessLogic: {
title: 'Implementacija poslovne logike',
validation: {
title: 'Validacija vremenskih unosa',
description: 'Logika validacije osigurava da su sva poslovna pravila ispoštovana:',
code: `def validate_time_entry_creation(data: dict, user_id: int) -> None:
'''Validates a new time entry according to business rules.'''
# Check for existing incomplete entries
incomplete_entry = TimeEntry.query.filter_by(
personal_id=user_id,
gehen=None,
datum=data['date']
).first()
if incomplete_entry:
raise ValidationError('Cannot create new entry while incomplete entry exists')
# Check for time overlap with existing entries
overlapping_entry = TimeEntry.query.filter(
TimeEntry.personal_id == user_id,
TimeEntry.datum == data['date'],
TimeEntry.kommen <= data['checkIn'],
TimeEntry.gehen >= data['checkIn']
).first()
if overlapping_entry:
raise ValidationError('Time entry overlaps with existing entry')`
}
},
databaseDesign: {
title: 'Dizajn baze podataka',
description: 'MSSQL šema baze podataka je dizajnirana za efikasnost i integritet:',
code: `CREATE TABLE dbo.Stundenzettel (
ID decimal NOT NULL PRIMARY KEY,
Personal_ID decimal,
Datum date,
Kommen time,
Gehen time,
xStatus int,
xBenutzer nvarchar(15),
xDatum datetime,
xVersion timestamp
);
CREATE INDEX idx_personal_datum
ON dbo.Stundenzettel(Personal_ID, Datum);`
},
security: {
title: 'Implementacija sigurnosti',
authentication: {
title: 'JWT autentifikacija',
code: `# auth/jwt_handler.py
from flask_jwt_extended import create_access_token
def authenticate_user(username: str, password: str) -> str:
user = Personal.query.filter_by(
Benutzername=username,
Passwort=password # In production, use proper password hashing
).first()
if not user:
raise AuthenticationError('Invalid credentials')
return create_access_token(identity=user.ID)`
}
},
bestPractices: {
title: 'Najbolje prakse i naučene lekcije',
points: [
{
title: 'Validacija podataka na više nivoa',
items: [
'Frontend validacija za trenutni feedback',
'Backend validacija za poslovna pravila',
'Database constraints za integritet podataka'
]
},
{
title: 'Rukovanje greškama',
items: [
'Strukturirane poruke o greškama',
'Korisnički prijateljske poruke o greškama na frontendu',
'Detaljno logovanje na backendu'
]
},
{
title: 'Optimizacija performansi',
items: [
'Indeksiranje kritičnih polja u bazi',
'Frontend keširanje vremenskih unosa',
'Lazy loading za istorijske podatke'
]
}
]
},
challenges: {
title: 'Izazovi i rešenja',
timezones: {
title: '1. Rukovanje vremenskim zonama',
description: 'Poseban izazov je bilo ispravno rukovanje vremenskim zonama:',
code: `// utils/dateTime.ts
export const formatTimeForDisplay = (time: string): string => {
return new Date(\`1970-01-01T\${time}\`).toLocaleTimeString('de-DE', {
hour: '2-digit',
minute: '2-digit'
});
};
export const formatTimeForAPI = (time: string): string => {
return new Date(\`1970-01-01T\${time}\`).toISOString().split('T')[1];
};`
},
concurrency: {
title: '2. Istovremena ažuriranja',
description: 'Rukovanje istovremenim ažuriranjima je zahtevalo posebnu pažnju:',
code: `from sqlalchemy import and_, or_
def update_time_entry(entry_id: int, data: dict) -> TimeEntry:
entry = TimeEntry.query.filter_by(id=entry_id).with_for_update().first()
if not entry:
raise NotFoundError('Time entry not found')
# Optimistic locking using version field
if entry.xVersion != data['version']:
raise ConcurrencyError('Entry was modified by another user')
entry.gehen = data.get('checkOut')
db.session.commit()
return entry`
},
offline: {
title: '3. Offline funkcionalnost',
description: 'Za offline funkcionalnost implementirali smo Service Worker strategiju:',
code: `// service-worker.ts
const CACHE_NAME = 'timetracking-v1';
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(response => {
return caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});`
}
},
conclusion: {
title: 'Zaključak',
description: 'Razvoj rešenja za evidenciju radnog vremena zahteva pažljivo planiranje i razmatranje brojnih poslovnih pravila. Korišćenjem modernih tehnologija kao što su Next.js, TypeScript i Flask, uspeli smo da implementiramo robusno i korisnički prijateljsko rešenje.',
keyPoints: [
'Striktna tipizacija sa TypeScript-om',
'Sveobuhvatna logika validacije',
'Efikasan dizajn baze podataka',
'Korisnički prijateljsko rukovanje greškama'
],
results: 'Rešenje je uspešno u upotrebi već nekoliko meseci i pouzdano obrađuje stotine vremenskih unosa dnevno.'
}
}
};
@@ -0,0 +1,204 @@
// src/i18n/locales/sr/blog/posts/rfid-automation.ts
export const rfidAutomation = {
meta: {
title: 'RFID automatizacija etiketa: Od baze podataka do štampača',
date: '2024-02-09',
excerpt: 'Detaljna tehnička analiza implementacije automatizovanog sistema za štampanje RFID etiketa sa Python-om',
category: 'Sistemska integracija',
coverImage: '/images/posts/rfid-automation/cover.jpg',
tags: ['RFID', 'Python', 'ZPL', 'Automatizacija', 'Zebra štampač', 'EPC']
},
content: {
intro: {
title: 'RFID automatizacija etiketa: Od baze podataka do štampača',
description: 'U modernim logističkim i maloprodajnim okruženjima, efikasno i besprekorno označavanje proizvoda RFID tagovima je od ključnog značaja. U ovom članku delim svoja iskustva u implementaciji automatizovanog rešenja za generisanje i štampanje RFID etiketa sa kodiranjem čipa.'
},
requirements: {
title: 'Pozadina projekta',
points: [
'Automatsko generisanje EPC kodova (Electronic Product Code)',
'Kreiranje ZPL koda za Zebra štampače',
'Direktna mrežna komunikacija sa štampačem',
'Integracija sa postojećim podacima o proizvodima',
'Rukovanje greškama i logovanje'
]
},
implementation: {
title: 'Tehnička implementacija',
epcGeneration: {
title: 'Generisanje EPC koda',
description: 'EPC kodovi se generišu prema SGTIN standardu (Serialized Global Trade Item Number):',
code: `def generate_encoded_epc(company_prefix, indicator, item_ref, serial):
sgtin = SGTIN(company_prefix, indicator, item_ref, serial)
return sgtin.encode()`
},
zplTemplates: {
title: 'Upravljanje ZPL šablonima',
description: 'Za različite tipove etiketa implementirani su ZPL šabloni:',
code: `def generate_zpl_code(artikelnr, description, ean, price, material, water_resistance, glass_type, encoded_epc):
formatted_price = f'{price:.2f}'
return f'''
CT~~CD,~CC^~CT~
^XA
~TA000
~JSN
^LT35
^MNW
^MTT
^PON
^PMN
^LH0,0
^JMA
^PR2,2
~SD23
^JUS
^LRN
^CI27
^PA0,1,1,0
^RS8,,,3
^XZ
^XA
^MMT
^PW413
^LL531
^LS-24
^FT150,57^A0N,33,33^FH\\^CI27^FD{artikelnr}^FS^CI27
^FT44,86^A0N,21,20^FH\\^CI27^FD{description}^FS^CI27
^FT130,141^A0N,50,51^FH\\^CI27^FD{formatted_price} €^FS^CI27
^FT167,175^A0N,21,20^FH\\^CI27^FD{material}^FS^CI27
^FT185,201^A0N,21,20^FH\\^CI27^FD{water_resistance}^FS^CI27
^FT155,227^A0N,21,20^FH\\^CI27^FD{glass_type}^FS^CI27
^BY3,2,113^FT73,420^BEN,,Y,N
^FH\\^FD{ean}^FS
^RFW,H,1,2,1^FD3000^FS
^RFW,H,2,12,1^FD{encoded_epc}^FS
^PQ1,0,1,Y
^XZ'''`
},
printerCommunication: {
title: 'Mrežna komunikacija sa štampačem',
description: 'Komunikacija sa Zebra štampačem se odvija preko TCP/IP:',
code: `def send_to_printer(data, printer_ip='192.168.68.50', printer_port=9100):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((printer_ip, printer_port))
sock.sendall(data.encode('utf-8'))
logger.info('Podaci uspešno poslati štampaču')
except Exception as e:
logger.error(f'Greška pri slanju podataka štampaču: {e}')`
},
serialNumberManagement: {
title: 'Obrada podataka i upravljanje serijskim brojevima',
description: 'Upravljanje serijskim brojevima je kritično za jedinstvenost EPC kodova:',
code: `def initialize_serial_number():
global current_serial_number
try:
serial_log_content = SERIAL_NUMBER_LOG_PATH.read_text().strip()
current_serial_number = int(serial_log_content)
except (FileNotFoundError, ValueError):
current_serial_number = START_SERIAL_NUMBER
def get_next_serial_number():
global current_serial_number
current_serial_number += 1
return current_serial_number
def finalize_serial_number():
SERIAL_NUMBER_LOG_PATH.write_text(str(current_serial_number))`
}
},
features: {
title: 'Implementirane funkcionalnosti',
errorHandling: {
title: '1. Robusno rukovanje greškama',
points: [
'Validacija ulaznih podataka',
'Provera mrežne veze',
'Perzistencija serijskih brojeva',
'Detaljno logovanje svih operacija'
]
},
configurability: {
title: '2. Konfigurabilnost',
points: [
'Podesiva IP adresa i port štampača',
'Prilagodljivi ZPL šabloni',
'Fleksibilno generisanje EPC kodova',
'Podesivi opsezi serijskih brojeva'
]
},
scalability: {
title: '3. Skalabilnost',
points: [
'Batch obrada podataka o proizvodima',
'Mogući paralelni zadaci štampanja',
'Efikasno upravljanje resursima',
'Modularan kod za jednostavno proširivanje'
]
}
},
bestPractices: {
title: 'Najbolje prakse',
dataValidation: {
title: '1. Validacija podataka',
points: [
'Striktna tipizacija za kritična polja podataka',
'Provera obaveznih polja',
'Provere formata i verodostojnosti'
]
},
faultTolerance: {
title: '2. Tolerancija na greške',
points: [
'Automatski pokušaji ponavljanja',
'Graceful degradacija',
'Detaljni zapisi o greškama'
]
},
maintainability: {
title: '3. Održivost',
points: [
'Modularna struktura koda',
'Detaljna dokumentacija',
'Jasno odvajanje konfiguracije i koda'
]
}
},
lessonsLearned: {
title: 'Naučene lekcije',
zplSpecifics: {
title: '1. ZPL specifičnosti',
points: [
'Neophodno precizno poznavanje ZPL specifikacija',
'Pažljiva validacija generisanih ZPL kodova',
'Redovno testiranje sa različitim modelima štampača'
]
},
rfidStandards: {
title: '2. RFID standardi',
points: [
'Kritično poštovanje EPC standarda',
'Pažljivo upravljanje serijskim brojevima',
'Validacija generisanih EPC kodova'
]
},
networkCommunication: {
title: '3. Mrežna komunikacija',
points: [
'Robusno rukovanje mrežnim problemima',
'Tajmauti i pokušaji ponavljanja',
'Baferovanje zadataka štampanja'
]
}
},
conclusion: {
title: 'Zaključak',
description: 'Implementirano rešenje omogućava efikasnu i pouzdanu automatizaciju procesa RFID označavanja. Kombinacijom generisanja EPC kodova, upravljanja ZPL šablonima i direktne komunikacije sa štampačem, kreiran je robustan sistem koji se dokazao u praksi.',
keyPoints: [
'Temeljno planiranje sistemske arhitekture',
'Sveobuhvatno rukovanje greškama',
'Pažljiva dokumentacija',
'Redovno testiranje i validacija'
],
results: 'Rešenje stabilno radi u produkciji već nekoliko meseci i svakodnevno obrađuje stotine etiketa.'
}
}
};
+99
View File
@@ -0,0 +1,99 @@
export const common = {
// SEO & Meta
siteTitle: 'Damjan Savić - Digitalna rešenja & JTL integracija',
siteDescription: 'Programer individualnih rešenja za automatizaciju procesa',
// Navigation
nav: {
home: 'Početna',
about: 'O meni',
services: 'Usluge',
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Kontakt'
},
// Common Actions
actions: {
readMore: 'Pročitaj više',
viewMore: 'Prikaži više',
viewAll: 'Prikaži sve',
back: 'Nazad',
close: 'Zatvori',
submit: 'Pošalji',
loading: 'Učitavanje...'
},
// UI Components
ui: {
published: 'Objavljeno',
lastUpdated: 'Poslednje ažuriranje',
category: 'Kategorija',
categories: 'Kategorije',
tag: 'Oznaka',
tags: 'Oznake',
author: 'Autor',
minuteRead: 'minuta čitanja',
tableOfContents: 'Sadržaj'
},
// Error Messages
errors: {
generic: 'Došlo je do greške',
notFound: 'Stranica nije pronađena',
loading: 'Greška pri učitavanju',
return: 'Povratak na početnu stranicu'
},
// Loading States
loading: {
content: 'Učitavanje sadržaja',
page: 'Učitavanje stranice',
processing: 'Obrada u toku'
},
// Dates
dates: {
months: {
long: [
'Januar', 'Februar', 'Mart', 'April', 'Maj', 'Jun',
'Jul', 'Avgust', 'Septembar', 'Oktobar', 'Novembar', 'Decembar'
],
short: [
'Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun',
'Jul', 'Avg', 'Sep', 'Okt', 'Nov', 'Dec'
]
},
weekdays: {
long: [
'Nedelja', 'Ponedeljak', 'Utorak', 'Sreda',
'Četvrtak', 'Petak', 'Subota'
],
short: ['Ned', 'Pon', 'Uto', 'Sre', 'Čet', 'Pet', 'Sub']
}
},
// Social Media
social: {
followMe: 'Pratite me na',
shareOn: 'Podeli na',
linkedin: 'LinkedIn',
github: 'GitHub',
email: 'E-mail'
},
// Contact Form
contact: {
title: 'Kontakt',
name: 'Ime',
email: 'E-mail',
message: 'Poruka',
submit: 'Pošalji poruku',
success: 'Vaša poruka je uspešno poslata',
error: 'Došlo je do greške pri slanju vaše poruke'
},
// Accessibility
a11y: {
skipToContent: 'Preskoči na glavni sadržaj',
menuOpen: 'Otvori meni',
menuClose: 'Zatvori meni',
darkMode: 'Promeni tamni režim',
carousel: {
next: 'Sledeća slika',
previous: 'Prethodna slika'
}
}
} as const;
export type CommonTranslations = typeof common;
+9
View File
@@ -0,0 +1,9 @@
const cookiebanner = {
cookies: {
message: "Ovaj sajt koristi kolačiće za bolje iskustvo pretraživanja. Podaci neće biti deljeni sa trećim licima.",
accept: "Prihvati kolačiće",
decline: "Odbij"
}
};
export default cookiebanner;
+40
View File
@@ -0,0 +1,40 @@
// src/i18n/locales/sr/footer.ts
const footer = {
sections: {
contact: {
title: "Kontakt",
email: "info@damjan-savic.com",
location: "Keln, Nemačka",
aria: {
emailLink: "Pošalji email",
locationText: "Lokacija"
}
},
navigation: {
title: "Navigacija",
links: {
portfolio: "Portfolio",
blog: "Blog",
about: "O meni",
contact: "Kontakt"
}
},
social: {
title: "Društvene mreže",
aria: {
linkedin: "Posetite moj LinkedIn profil",
github: "Posetite moj GitHub profil"
}
}
},
legal: {
copyright: "Sva prava zadržana",
links: {
privacy: "Zaštita podataka",
terms: "Impresum"
}
}
} as const;
export default footer;
export type FooterTranslations = typeof footer;
+109
View File
@@ -0,0 +1,109 @@
// src/i18n/locales/sr/index.ts
// Prevodi blog postova
import { erpIntegrationBreuninger } from './blog/posts/erp-integration-breuninger';
import { fullstackDevelopmentTimetracking } from './blog/posts/fullstack-development-timetracking';
import { rfidAutomation as blogRfidAutomation } from './blog/posts/rfid-automation';
import { blog } from './blog';
// Prevodi stranica
import { about } from './pages/about/index';
import { contact } from './pages/contact/index';
import { dashboard } from './pages/dashboard';
import { home } from './pages/home/index';
import { login } from './pages/login';
import { notfound } from './pages/notfound';
import { portfolio as portfolioPage } from './pages/portfolio';
import { privacy } from './pages/privacy';
import { terms } from './pages/terms';
// Prevodi portfolio projekata
import { aiDataReader } from './portfolio/projects/ai-data-reader';
import { portfolio } from './portfolio';
// Zajednički prevodi i konfiguracije
import { common } from './common';
import { meta } from './meta';
import { navigation } from './navigation';
// Footer prevodi
import footer from './footer';
// Objedinjavanje svih prevoda
const translations = {
// Stranice
pages: {
about,
contact,
dashboard,
home,
login,
notfound,
portfolio: portfolioPage,
privacy,
terms,
},
// Blog
blog: {
...blog,
posts: {
erpIntegrationBreuninger,
fullstackDevelopmentTimetracking,
rfidAutomation: blogRfidAutomation,
},
},
// Portfolio
portfolio: {
...portfolio,
projects: {
aiDataReader,
},
},
// Footer
footer,
// Zajedničke konfiguracije
common: {
...common,
cookies: {
message: "Ovaj sajt koristi kolačiće kako bi poboljšao vaše iskustvo pretraživanja i pružio personalizovan sadržaj. Prikupljeni podaci neće biti deljeni sa trećim licima.",
accept: "Prihvati kolačiće",
decline: "Odbij"
}
},
meta,
navigation,
} as const;
// Default izvoz: kompletan objekat prevoda
export default translations;
// Definicija tipa za prevode
export type Translations = typeof translations;
// Re-izvoz za direktan pristup pojedinačnim modulima
export {
// Stranice
about,
contact,
dashboard,
home,
login,
notfound,
portfolioPage as portfolioPageTranslations,
privacy,
terms,
// Blog
blog,
erpIntegrationBreuninger,
fullstackDevelopmentTimetracking,
blogRfidAutomation as blogRfidAutomationPost,
// Portfolio
portfolio,
aiDataReader,
// Footer
footer,
// Zajedničko
common,
meta,
navigation,
};
+93
View File
@@ -0,0 +1,93 @@
export const meta = {
site: {
name: 'Damjan Savić',
title: 'Damjan Savić - Digital Solutions & JTL Integration',
subtitle: 'Programer individualnih rešenja za automatizaciju procesa',
description: 'Sa iskustvom u razvoju softvera i ekspertizom u digitalnoj transformaciji, podržavam kompanije u optimizaciji i automatizaciji njihovih poslovnih procesa.',
keywords: [
'JTL integracija',
'E-commerce rešenja',
'Automatizacija procesa',
'Digitalno savetovanje',
'ERP sistemi',
'Python razvoj',
'Sistemska integracija',
'Digitalni marketing'
].join(', ')
},
company: {
name: 'CoderConda',
shortName: 'CoderConda',
description: 'Vaš JTL-servisni partner za brza, pouzdana i ekonomična rešenja.',
address: 'Rotdornallee',
city: 'Köln',
postalCode: '50999',
country: 'Nemačka',
phone: '+49 175 695 0979',
email: 'info@damjan-savic.com',
website: 'www.damjan-savic.com'
},
author: {
name: 'Damjan Savić',
role: 'Konsultant za digitalna rešenja',
company: 'CoderCond',
location: 'Oberhausen, Nemačka',
email: 'info@damjan-savic.com',
website: 'https://www.damjan-savic.com',
languages: [
{ code: 'en', level: 'C2', name: 'Engleski' },
{ code: 'sr', level: 'C2', name: 'Srpski' },
{ code: 'de', level: 'C2', name: 'Nemački' },
{ code: 'fr', level: 'B2', name: 'Francuski' },
{ code: 'es', level: 'B2', name: 'Španski' },
{ code: 'ru', level: 'A1', name: 'Ruski' }
]
},
social: {
linkedin: 'https://www.linkedin.com/in/damjansavic/',
github: 'https://github.com/damjansavic',
email: 'info@damjan-savic.com'
},
expertise: {
areas: [
'JTL integracija i savetovanje',
'Automatizacija procesa',
'E-commerce razvoj',
'Sistemska integracija',
'ERP sistemi',
'Digitalna transformacija'
],
technologies: [
'Python',
'React/Next.js',
'MariaDB',
'Docker',
'JTL-WaWi',
'Shopify',
'Shopware'
]
},
seo: {
defaultLanguage: 'de',
alternateLanguages: ['en', 'sr'],
robots: 'index, follow',
googleSiteVerification: '', // Po potrebi
og: {
type: 'website',
locale: 'sr_RS',
siteName: 'Damjan Savić - Digital Solutions',
images: {
url: '/images/og-image.jpg',
width: 1200,
height: 630,
alt: 'Damjan Savić - Digital Solutions & JTL Integration'
}
},
twitter: {
card: 'summary_large_image',
site: '@damjansavic',
creator: '@damjansavic'
}
}
} as const;
export type MetaConfig = typeof meta;
+79
View File
@@ -0,0 +1,79 @@
// C:\Development\Damjan Savic\Portfolio\src\i18n\locales\sr\navigation.ts
export const navigation = {
// Glavna navigacija
main: {
home: 'Početna',
about: 'O meni',
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Kontakt'
},
// Dashboard i Admin
admin: {
login: 'Prijava',
dashboard: 'Dashboard',
logout: 'Odjava'
},
// Footer navigacija
footer: {
legal: {
privacy: 'Politika privatnosti',
terms: 'Uslovi korišćenja',
imprint: 'Impresum'
},
sections: {
portfolio: 'Portfolio',
blog: 'Blog',
contact: 'Kontakt'
}
},
// Sekcije stranice
sections: {
experience: 'Iskustvo',
skills: 'Veštine',
projects: 'Projekti',
about: 'O meni'
},
// Breadcrumbs i navigacija za povratak
navigation: {
backTo: {
home: 'Nazad na početnu',
portfolio: 'Nazad na portfolio',
blog: 'Nazad na blog'
},
breadcrumbs: {
home: 'Početna',
portfolio: 'Portfolio',
blog: 'Blog',
about: 'O meni',
contact: 'Kontakt'
}
},
// Mobile navigacija
mobile: {
menu: 'Meni',
close: 'Zatvori',
open: 'Otvori meni'
},
// URL-ovi (za dinamičko generisanje ruta)
urls: {
home: '/',
about: '/about',
portfolio: '/portfolio',
blog: '/blog',
contact: '/contact',
login: '/login',
dashboard: '/dashboard',
privacy: '/privacy',
terms: '/terms'
},
// Meta informacije za navigaciju
meta: {
main: 'Glavna navigacija',
footer: 'Footer navigacija',
social: 'Navigacija društvenih mreža',
legal: 'Pravna navigacija'
}
} as const;
export type NavigationConfig = typeof navigation;
+33
View File
@@ -0,0 +1,33 @@
export const hero = {
// Navigation/Header
aboutMe: 'O MENI',
// Main Section
title: 'Ekspert za digitalna rešenja',
description: 'Sa iskustvom u razvoju softvera i ekspertizom u digitalnoj transformaciji, pomažem kompanijama da optimizuju i automatizuju svoje procese kroz inovativna rešenja.',
// Expertise Areas
expertise: {
processAutomation: {
title: 'Automatizacija procesa',
description: 'Razvoj efikasnih automatizovanih tokova rada'
},
systemIntegration: {
title: 'Integracija sistema',
description: 'Povezivanje i optimizacija poslovnih sistema'
},
customDevelopment: {
title: 'Individualni razvoj',
description: 'Izrada prilagođenih softverskih rešenja'
}
},
// Languages
languages: {
english: 'Engleski',
serbian: 'Srpski',
german: 'Nemački',
french: 'Francuski',
spanish: 'Španski',
russian: 'Ruski'
}
} as const;
// Type for type safety
export type HeroTranslations = typeof hero;
+24
View File
@@ -0,0 +1,24 @@
import { hero } from './hero';
import { journey } from './journey';
import { schema } from './schema';
import { skillbar } from './skillbar';
import { skillgroup } from './skillgroup';
import { skills } from './skills';
import { workflow } from './workflow';
export const about = {
hero,
journey,
schema,
skillbar,
skillgroup,
skills,
workflow
} as const;
// Typen exportieren
export type { HeroTranslations } from './hero';
export type { JourneyTranslations } from './journey';
export type { SchemaTranslations } from './schema';
export type { SkillBarTranslations } from './skillbar';
export type { SkillGroupTranslations } from './skillgroup';
export type { SkillsTranslations } from './skills';
export type { WorkflowTranslations } from './workflow';
@@ -0,0 +1,96 @@
export const journey = {
// Header
title: 'Profesionalni razvoj',
subtitle: 'Od digitalnih medija do poslovnih rešenja',
// Education Section
education: {
title: 'Obrazovanje',
degrees: {
masters: {
degree: 'M.A. Razvoj softvera',
university: 'Middlesex University, London',
period: '2020 - 2022'
},
bachelors: {
degree: 'B.A. Cross-Media produkcija',
university: 'Middlesex University, London',
period: '2018 - 2020'
}
}
},
// Languages Section
languages: {
title: 'Jezici',
items: {
english: {
name: 'Engleski',
level: 'C2'
},
serbian: {
name: 'Srpski',
level: 'C2'
},
german: {
name: 'Nemački',
level: 'C2'
},
french: {
name: 'Francuski',
level: 'B2'
},
spanish: {
name: 'Španski',
level: 'B2'
},
russian: {
name: 'Ruski',
level: 'A1'
}
}
},
// Work History
work: {
positions: [
{
period: '08/2023 - Danas',
company: 'Ritter Digital GmbH',
title: 'Digital Solutions Consultant',
location: 'Oberhausen',
highlights: [
'ERP konsalting i implementacija (JTL WaWi)',
'Automatizacija procesa i Full-Stack razvoj',
'RFID tehnologija i automatizacija',
'Generisanje i upravljanje Lead-ovima',
'Content menadžment podržan AI tehnologijom'
]
},
{
period: '02/2023 - 08/2023',
company: 'Joyce & Girls Co AG',
title: 'ERP Integration Specialist',
location: 'Köln',
highlights: [
'Kompleksna integracija sistema (Apparel Magic, TradeByte)',
'Administracija servera i automatizacija',
'Razvoj baza podataka i API-ja',
'Digitalni marketing i analiza kampanja'
]
},
{
period: '08/2022 - 01/2023',
company: 'Magnarius',
title: 'RPA Developer & E-Commerce Manager',
location: 'Bergisch Gladbach',
highlights: [
'Shopware 6 razvoj i JTL integracija',
'Google Ads automatizacija',
'CMS menadžment i optimizacija',
'Implementacija SEO strategije'
]
}
]
}
} as const;
// Tip za tipsku sigurnost
export type JourneyTranslations = typeof journey;
+31
View File
@@ -0,0 +1,31 @@
export const schema = {
page: {
name: 'O Damjanu Saviću',
description: 'Saznajte više o Damjanu Saviću, sertifikovanom JTL ekspertu sa velikim iskustvom u e-trgovini i sistemima za upravljanje robom.'
},
person: {
jobTitle: 'JTL integracioni ekspert',
description: 'Sa bogatim iskustvom u integraciji i optimizaciji e-commerce sistema, pomažem kompanijama u digitalnoj transformaciji njihovih poslovnih procesa.',
languages: {
english: 'Engleski',
serbian: 'Srpski',
german: 'Nemački',
french: 'Francuski',
spanish: 'Španski',
russian: 'Ruski'
},
skills: {
python: 'Python',
googleAds: 'Google Ads',
metaAds: 'Meta Ads',
shopware: 'Shopware',
shopify: 'Shopify',
wooCommerce: 'WooCommerce',
jtlWawi: 'JTL WAWI',
serverAdmin: 'Administracija servera',
airflow: 'AirFlow'
}
}
} as const;
// Tip za tipsku sigurnost
export type SchemaTranslations = typeof schema;
@@ -0,0 +1,13 @@
export const skillbar = {
// Accessibility labels
ariaLabel: {
skillLevel: 'Nivo veštine',
progressBar: 'Indikator napretka'
},
// Screen reader text
screenReader: {
progress: '{{level}} procenata napretka za {{skill}}'
}
} as const;
// Tip za tipsku sigurnost
export type SkillBarTranslations = typeof skillbar;
@@ -0,0 +1,63 @@
export const skillgroup = {
// Kategorije
categories: {
development: 'Razvoj',
ecommerce: 'E-Commerce',
marketing: 'Marketing',
automation: 'Automatizacija',
languages: 'Programski jezici',
databases: 'Baze podataka'
},
// Veštine po kategorijama
skills: {
development: {
frontend: 'Frontend razvoj',
backend: 'Backend razvoj',
fullstack: 'Full-Stack razvoj',
api: 'API razvoj',
testing: 'Testiranje softvera'
},
ecommerce: {
jtl: 'JTL WaWi',
shopware: 'Shopware',
shopify: 'Shopify',
woocommerce: 'WooCommerce',
magento: 'Magento'
},
marketing: {
seo: 'Optimizacija za pretraživače',
sea: 'Marketing na pretraživačima',
analytics: 'Web analitika',
googleAds: 'Google Ads',
metaAds: 'Meta Ads'
},
automation: {
rpa: 'Robotska automatizacija procesa',
workflow: 'Automatizacija radnih tokova',
cicd: 'CI/CD',
testing: 'Automatizacija testiranja',
deployment: 'Automatizacija razvoja'
},
languages: {
python: 'Python',
javascript: 'JavaScript',
typescript: 'TypeScript',
php: 'PHP',
sql: 'SQL'
},
databases: {
mysql: 'MySQL',
postgresql: 'PostgreSQL',
mongodb: 'MongoDB',
redis: 'Redis',
elasticsearch: 'Elasticsearch'
}
},
// Pristupačnost
ariaLabels: {
skillGroup: 'Grupa veština',
skillList: 'Lista veština u ovoj kategoriji'
}
} as const;
// Tip za tipsku sigurnost
export type SkillGroupTranslations = typeof skillgroup;
+46
View File
@@ -0,0 +1,46 @@
// sr/pages/about/skills.ts
export const skills = {
title: 'Veštine',
skillGroups: [
{
category: 'Razvoj',
items: [
{ name: 'Python', level: 90 },
{ name: 'Google Ads', level: 85 },
{ name: 'Meta Ads', level: 85 }
]
},
{
category: 'E-Commerce',
items: [
{ name: 'Shopware', level: 85 },
{ name: 'Shopify', level: 85 },
{ name: 'WooCommerce', level: 85 }
]
},
{
category: 'Administracija sistema',
items: [
{ name: 'JTL WAWI', level: 85 },
{ name: 'Server', level: 75 },
{ name: 'AirFlow', level: 60 }
]
}
],
ui: {
percentage: 'procenat',
levelLabel: 'nivo',
skillLevel: '{{level}}% ovladanosti za {{skill}}'
},
aria: {
skillGroup: 'Grupa veština za {{category}}',
skillBar: 'Indikator napretka za {{skill}}',
skillIcon: 'Ikona za {{category}}',
selectSkill: 'Izaberi veštinu'
},
screenReader: {
skillProgress: '{{skill}} sa nivoom od {{level}} procenata'
}
} as const;
export type SkillsTranslations = typeof skills;
@@ -0,0 +1,44 @@
export const workflow = {
// Naslov stranice
title: 'MOJ WORKFLOW',
description: 'Sistematski pristup razvoju softvera kroz definisane korake',
// Workflow koraci
steps: [
{
number: '01',
title: 'ANALIZA ZAHTEVA'
},
{
number: '02',
title: 'PROVERA ROKOVA I OGRANIČENJA'
},
{
number: '03',
title: 'POSTAVLJANJE RAZVOJNOG OKRUŽENJA'
},
{
number: '04',
title: 'PROGRAMIRANJE'
},
{
number: '05',
title: 'TESTIRANJE REZULTATA'
},
{
number: '06',
title: 'PODRŠKA I SKALIRANJE KODA'
}
],
// Aria oznake za pristupačnost
aria: {
workflowSection: 'Workflow proces',
stepNumber: 'Korak {{number}}',
stepDescription: 'Workflow korak: {{title}}'
},
// Tekstovi za čitače ekrana
screenReader: {
stepProgress: 'Korak {{number}} od {{total}}: {{title}}'
}
} as const;
// Tip za tipsku sigurnost
export type WorkflowTranslations = typeof workflow;
@@ -0,0 +1,41 @@
// src/i18n/locales/sr/pages/contact/contactform.ts
export const contactform = {
// Zaglavlje formulara
title: 'Kontaktirajte me',
description: 'Imate pitanja ili želite da sarađujemo? Pošaljite mi poruku.',
// Polja formulara
name: {
label: 'Ime',
placeholder: 'Vaše puno ime'
},
email: {
label: 'E-mail',
placeholder: 'vasa.adresa@primer.com'
},
message: {
label: 'Poruka',
placeholder: 'Vaša poruka za mene...'
},
// Dugme
submit: 'Pošalji poruku',
// Status poruke
successMessage: 'Hvala vam na poruci! Javiću vam se u najkraćem mogućem roku.',
errorMessage: 'Izvinite, došlo je do greške prilikom slanja vaše poruke. Molimo pokušajte ponovo kasnije.',
// Poruke o greškama
errors: {
nameRequired: 'Molimo unesite vaše ime',
emailRequired: 'Molimo unesite vašu e-mail adresu',
emailInvalid: 'Molimo unesite ispravnu e-mail adresu',
messageRequired: 'Molimo unesite poruku'
},
// Aria oznake
aria: {
form: 'Kontakt formular',
submitting: 'Slanje formulara',
successAlert: 'Poruka o uspehu',
errorAlert: 'Poruka o grešci'
}
} as const;
// Tip za tipsku sigurnost
export type ContactFormTranslations = typeof contactform;
@@ -0,0 +1,27 @@
// src/i18n/locales/sr/pages/contact/contactinfo.ts
export const contactinfo = {
// Zaglavlje
title: 'Kontakt informacije',
description: 'Možete me kontaktirati na sledeće načine',
// Oznake kontakt metoda
addressLabel: 'Lokacija kancelarije',
phoneLabel: 'Telefon',
emailLabel: 'E-mail',
// Kontakt informacije
address: 'Rotdornallee, Köln',
phone: '+49 175 695 0979',
email: 'info@damjan-savic.com',
// Dodatne informacije
availabilityNote: 'Radno vreme: ponedeljak - petak, 9:00 - 17:00',
// Aria oznake
aria: {
contactCard: 'Kartica kontakt informacija',
addressLink: 'Otvori lokaciju u Google Maps',
phoneLink: 'Pozovi',
emailLink: 'Pošalji e-mail',
externalLink: 'Otvara se u novom tabu'
}
} as const;
// Tip za tipsku sigurnost
export type ContactInfoTranslations = typeof contactinfo;
@@ -0,0 +1,71 @@
// src/i18n/locales/sr/pages/contact/index.ts
export const contact = {
breadcrumb: "KONTAKT",
hero: {
title: "Radimo Zajedno",
subtitle: "Imate projekat na umu? Hajde da razgovaramo o tome kako vam možemo pomoći da ostvarite svoje ciljeve."
},
contactInfo: {
title: "Kontakt informacije",
description: "Možete me kontaktirati na sledeće načine",
address: {
label: "Lokacija kancelarije",
value: "Rotdornalle, Köln"
},
phone: {
label: "Telefon",
value: "+49 175 695 0979"
},
email: {
label: "E-mail",
value: "info@damjan-savic.com"
},
availabilityNote: "Radno vreme: ponedeljak - petak, 9:00 - 17:00",
aria: {
contactCard: "Kartica kontakt informacija",
addressLink: "Otvori lokaciju u Google Maps",
phoneLink: "Pozovi",
emailLink: "Pošalji e-mail",
externalLink: "Otvara se u novom tabu"
}
},
contactForm: {
title: "Kontaktirajte me",
description: "Imate pitanja ili želite da sarađujemo? Pošaljite mi poruku.",
name: {
label: "Ime",
placeholder: "Vaše puno ime"
},
email: {
label: "E-mail",
placeholder: "vasa.adresa@primer.com"
},
message: {
label: "Poruka",
placeholder: "Vaša poruka za mene..."
},
submit: "Pošalji poruku",
successMessage: "Hvala vam na poruci! Javiću vam se u najkraćem mogućem roku.",
errorMessage: "Izvinite, došlo je do greške prilikom slanja vaše poruke. Molimo pokušajte ponovo kasnije.",
errors: {
nameRequired: "Molimo unesite vaše ime",
emailRequired: "Molimo unesite vašu e-mail adresu",
emailInvalid: "Molimo unesite ispravnu e-mail adresu",
messageRequired: "Molimo unesite poruku"
},
aria: {
form: "Kontakt formular",
submitting: "Slanje formulara",
successAlert: "Poruka o uspehu",
errorAlert: "Poruka o grešci"
}
}
} as const;
export type ContactTranslations = typeof contact;
export default {
pages: {
contact: contact
}
};
+76
View File
@@ -0,0 +1,76 @@
// src/i18n/locales/sr/pages/dashboard.ts
export const dashboard = {
// SEO
seo: {
title: 'Analitički dashboard',
description: 'Dashboard za analizu veb sajta'
},
// Glavni naslovi
header: {
title: 'Analitički dashboard',
activeUsers: 'aktivnih korisnika'
},
// Kartice sa metrikama
metrics: {
pageViews: {
title: 'Pregledi stranica',
perMinute: 'po minutu'
},
uniqueVisitors: {
title: 'Jedinstveni posetioci',
currentlyActive: 'trenutno aktivni'
},
conversions: {
title: 'Konverzije',
rate: 'Stopa konverzije'
},
timeOnSite: {
title: 'Prosečno vreme posete',
bounceRate: 'Stopa napuštanja'
}
},
// Sekcija najpopularnijih stranica
topPages: {
title: 'Najpopularnije stranice',
columns: {
path: 'Putanja',
views: 'Pregledi',
change: 'Promena'
}
},
// Sekcija za praćenje događaja
events: {
title: 'Praćenje događaja',
types: {
contactForm: 'Slanje kontakt forme',
portfolioView: 'Pregled portfolija',
cvDownload: 'Preuzimanje biografije',
blogRead: 'Čitanje bloga'
}
},
// Status poruke
status: {
loading: 'Učitavanje dashboard-a...',
error: 'Greška pri učitavanju podataka',
notAuthenticated: 'Molimo prijavite se'
},
// Ostalo
misc: {
viewMore: 'Prikaži više',
refresh: 'Osveži',
period: {
today: 'Danas',
yesterday: 'Juče',
last7Days: 'Poslednjih 7 dana',
last30Days: 'Poslednjih 30 dana',
thisMonth: 'Ovaj mesec',
lastMonth: 'Prošli mesec'
}
},
// Trendovi i promene
trends: {
increase: 'Porast',
decrease: 'Pad',
noChange: 'Bez promene'
}
};
+9
View File
@@ -0,0 +1,9 @@
// src/i18n/locales/sr/pages/home/about.ts
export const about = {
title: 'O Meni',
content: 'Kao konsultant u oblasti digitalizacije, pomažem kompanijama da unaprede svoje procese kroz savremeni softver. Razvijam rešenja za povezivanje sistema za upravljanje robom, programe za automatizaciju radnih procesa i RFID aplikacije za bolje praćenje robe. U kompaniji Ritter Digital GmbH radim sa JTL softverom i razvijam individualna programska rešenja. Jedan od projekata je bilo povezivanje Breuninger sistema sa Apparel Magic-om preko TB.One platforme. Moj cilj je da učinim kompanije efikasnijim kroz softver.',
image: {
alt: 'Portret Damjana Savića'
}
} as const;
export type AboutTranslations = typeof about;
@@ -0,0 +1,77 @@
// src/i18n/locales/sr/pages/home/experience.ts
export const experience = {
title: 'Radno iskustvo',
navigation: {
prev: '←',
next: '→'
},
positions: [
{
role: 'Consultant Digital Solutions & Developer',
company: 'RITTER Gesellschaft für digitale Geschäftsprozesse mbH',
period: '08/2023 - DANAS',
highlights: [
'JTL WaWi, WMS i POS konsalting i implementacija',
'Python-bazirana automatizaciona rešenja',
'RFID sistemi i GUI razvoj',
'AI i poslovna inteligencija'
]
},
{
role: 'ERP integracioni specijalista i E-Commerce developer',
company: 'Joyce & Girls',
period: '01/2023 - 08/2023',
highlights: [
'ApparelMagic i TradeByte integracija',
'MariaDB middleware razvoj',
'Windows Server administracija',
'Shopify optimizacija'
]
},
{
role: 'RPA Developer & E-Commerce Manager',
company: 'C&S Marketing',
period: '08/2022 - 01/2023',
highlights: [
'Shopware 6 i JTL integracija',
'Python automatizacija',
'Google Ads optimizacija',
'CMS menadžment'
]
},
{
role: 'E-Commerce Developer',
company: 'Brands Club GmbH',
period: '08/2021 - 07/2022',
highlights: [
'Shopify i JTL integracija',
'Server administracija',
'Produkcija sadržaja',
'Marketing automatizacija'
]
},
{
role: 'E-Commerce Developer',
company: 'Feine Uhren Eupen',
period: '01/2021 - 08/2021',
highlights: [
'Shopware 5 razvoj',
'Fotografija proizvoda',
'Prodaja u segmentu luksuznih satova',
'E-Commerce menadžment'
]
},
{
role: 'Online Marketing Manager',
company: 'Ufer8, Ambis, Teatro & Die Halle Tor 2',
period: '01/2018 - 12/2020',
highlights: [
'Social Media sadržaj',
'Event marketing',
'Organizacija događaja',
'Marketing automatizacija'
]
}
]
} as const;
export type ExperienceTranslations = typeof experience;
@@ -0,0 +1,27 @@
// src/i18n/locales/sr/pages/home/expertise.ts
export const expertise = {
title: 'Oblasti ekspertize',
areas: [
{
title: 'ERP Integracija',
description: 'Ekspert za JTL-Wawi implementaciju, konfiguraciju i optimizaciju. Specijalizovan za sisteme za upravljanje robom i POS integraciju.',
skills: ['JTL-Wawi', 'JTL-WMS', 'JTL-POS', 'Apparel Magic']
},
{
title: 'Razvoj',
description: 'Full-Stack razvoj sa fokusom na Python automatizaciju, React frontende i dizajn baza podataka.',
skills: ['Python', 'React/Next.js', 'MariaDB', 'Docker']
},
{
title: 'E-Commerce',
description: 'Obimno iskustvo sa različitim e-commerce platformama i integracijama sa marketplace-ima.',
skills: ['Shopify', 'Shopware', 'WooCommerce', 'API Integration']
},
{
title: 'Digitalni Marketing',
description: 'Strateški pristup u digitalnom marketingu sa fokusom na automatizaciju i analitiku.',
skills: ['Google Ads', 'Meta Ads', 'SEO', 'Analytics']
}
]
} as const;
export type ExpertiseTranslations = typeof expertise;
+28
View File
@@ -0,0 +1,28 @@
// src/i18n/locales/sr/pages/home/hero.ts
export const hero = {
title: 'SOFTWARE ENGINEER',
name: 'DAMJAN SAVIĆ',
cta: 'KONTAKTIRAJTE ME',
image: {
alt: 'Portret Damjana Savića'
},
social: {
getInTouch: 'Kontaktirajte me',
linkedin: {
title: 'Posetite moj LinkedIn profil'
},
github: {
title: 'Posetite moj GitHub profil'
},
email: {
title: 'Pošaljite mi e-mail'
}
},
navigation: {
experience: 'ISKUSTVO',
skills: 'VEŠTINE',
projects: 'PROJEKTI',
about: 'O MENI'
}
} as const;
export type HeroTranslations = typeof hero;
+25
View File
@@ -0,0 +1,25 @@
// src/i18n/locales/de/pages/home/index.ts
import { hero } from './hero';
import { about } from './about';
import { experience } from './experience';
import { expertise } from './expertise';
import { skills } from './skills';
import { projects } from './projects';
export const home = {
hero,
about,
experience,
expertise,
skills,
projects
} as const;
export type HomeTranslations = typeof home;
// Re-export individual sections for direct access
export {
hero,
about,
experience,
expertise,
skills,
projects
};
@@ -0,0 +1,10 @@
// src/i18n/locales/sr/pages/home/projects.ts
export const projects = {
title: 'Portfolio',
viewAll: 'Svi projekti →',
loading: 'Učitavanje projekata...',
error: {
loading: 'Greška pri učitavanju projekata'
}
} as const;
export type ProjectsTranslations = typeof projects;

Some files were not shown because too many files have changed in this diff Show More