Skip to content

Commit 77fbe4c

Browse files
committed
feat: add support for Norway with flag, band, and translations
1 parent 17eb870 commit 77fbe4c

8 files changed

Lines changed: 118 additions & 18 deletions

File tree

public/flags/no.svg

Lines changed: 7 additions & 0 deletions
Loading
92.5 KB
Binary file not shown.

src/app/globals.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
font-display: swap;
2525
}
2626

27+
@font-face {
28+
font-family: 'MyriadPro';
29+
src: url('/fonts/MyriadProSemiboldCondensed.ttf') format('truetype');
30+
font-weight: 600;
31+
font-style: normal;
32+
font-display: swap;
33+
}
34+
2735
@font-face {
2836
font-family: 'Google Sans';
2937
src: url('/fonts/GoogleSans-Regular.woff2') format('woff2');

src/components/LicensePlate.tsx

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, { forwardRef, useRef, useState, useLayoutEffect, useEffect } from
44
import { GermanPlateConfig, PlateStyle, GermanState, AustrianState, SwissCanton } from '@/types/plate';
55
import EUBand from './bands/EUBand';
66
import UKBand from './bands/UKBand';
7+
import NorwayBand from './bands/NorwayBand';
78
import StatePlakette from './plaketten/StatePlakette';
89
import AustrianStatePlakette from './plaketten/AustrianStatePlakette';
910
import HungarianCoatOfArms from './plaketten/HungarianCoatOfArms';
@@ -129,7 +130,8 @@ const LicensePlate = forwardRef<HTMLDivElement, LicensePlateProps>(
129130
document.fonts.load('105px EuroPlate'),
130131
document.fonts.load('105px "Google Sans"'),
131132
document.fonts.load('105px Tratex'),
132-
document.fonts.load('105px UKNumberPlate')
133+
document.fonts.load('105px UKNumberPlate'),
134+
document.fonts.load('600 105px MyriadPro')
133135
];
134136

135137
Promise.all(fontPromises).then(() => {
@@ -168,9 +170,9 @@ const LicensePlate = forwardRef<HTMLDivElement, LicensePlateProps>(
168170
const ukBandWidth = hasUkBand ? 40 * scale : 0; // UK band width when shown
169171

170172
// Available width for content (after EU band, borders, padding, and right band if present)
171-
// Switzerland (CH) has no EU band, UK (GB) has UK band instead
172-
const effectiveEuBandWidth = (country === 'CH' || country === 'GB') ? 0 : euBandWidth;
173-
const effectiveLeftOffset = country === 'GB' ? ukBandWidth : effectiveEuBandWidth;
173+
// Switzerland (CH) has no EU band, UK (GB) has UK band instead, Norway (N) has Norway band
174+
const effectiveEuBandWidth = (country === 'CH' || country === 'GB' || country === 'N') ? 0 : euBandWidth;
175+
const effectiveLeftOffset = country === 'GB' ? ukBandWidth : country === 'N' ? euBandWidth : effectiveEuBandWidth;
174176
const rightBandWidth = countryFeatures.hasRightBand ? euBandWidth : 0;
175177
const seasonalPlateWidth = (isGermany && seasonalPlate) ? 37 * scale : 0; // Reserve space for seasonal numbers
176178
const availableWidth = plateWidth - effectiveLeftOffset - rightBandWidth - seasonalPlateWidth - (borderWidth * 2) - (padding * 2);
@@ -229,6 +231,7 @@ const LicensePlate = forwardRef<HTMLDivElement, LicensePlateProps>(
229231
// Select font based on country
230232
const getFontFamily = () => {
231233
if (country === 'S') return 'Tratex, Normal';
234+
if (country === 'N') return 'MyriadPro, sans-serif';
232235
if (country === 'GB') return 'UKNumberPlate, sans-serif';
233236
return 'EuroPlate, sans-serif';
234237
};
@@ -394,8 +397,8 @@ const LicensePlate = forwardRef<HTMLDivElement, LicensePlateProps>(
394397
</>
395398
)}
396399

397-
{/* EU Band or German Flag for military - not shown for Switzerland or UK */}
398-
{country === 'CH' || country === 'GB' ? null : country === 'D' && cityCode === 'Y' ? (
400+
{/* EU Band or German Flag for military - not shown for Switzerland, UK, or Norway */}
401+
{country === 'CH' || country === 'GB' || country === 'N' ? null : country === 'D' && cityCode === 'Y' ? (
399402
/* German Flag for military plates */
400403
<div style={{
401404
position: 'absolute',
@@ -453,6 +456,19 @@ const LicensePlate = forwardRef<HTMLDivElement, LicensePlateProps>(
453456
</div>
454457
)}
455458

459+
{/* Norway Band - with flag and N country code */}
460+
{country === 'N' && (
461+
<div style={{
462+
position: 'absolute',
463+
left: 0,
464+
top: 0,
465+
bottom: 0,
466+
zIndex: 2,
467+
}}>
468+
<NorwayBand scale={scale} height="100%" borderRadius={5} />
469+
</div>
470+
)}
471+
456472
{/* Right band for France, Italy, Portugal */}
457473
{countryFeatures.hasRightBand && (
458474
<div style={{
@@ -482,7 +498,7 @@ const LicensePlate = forwardRef<HTMLDivElement, LicensePlateProps>(
482498
<div
483499
style={{
484500
position: 'absolute',
485-
left: country === 'CH' ? 0 : (country === 'GB' && hasUkBand) ? `${ukBandWidth}px` : country === 'GB' ? 0 : `${euBandWidth}px`,
501+
left: country === 'CH' ? 0 : (country === 'GB' && hasUkBand) ? `${ukBandWidth}px` : country === 'GB' ? 0 : country === 'N' ? `${euBandWidth}px` : `${euBandWidth}px`,
486502
right: countryFeatures.hasRightBand ? `${euBandWidth}px` : 0,
487503
top: 0,
488504
bottom: 0,

src/components/PlateGenerator.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const COUNTRY_FLAGS: Record<Country, string> = {
3232
'LT': '🇱🇹',
3333
'L': '🇱🇺',
3434
'M': '🇲🇹',
35+
'N': '🇳🇴',
3536
'NL': '🇳🇱',
3637
'PL': '🇵🇱',
3738
'P': '🇵🇹',
@@ -73,6 +74,7 @@ function getCountryDefaults(country: Country): { fontColor: string; backgroundCo
7374
case 'D': // Germany
7475
case 'A': // Austria (+ red stripes handled in LicensePlate)
7576
case 'E': // Spain
77+
case 'N': // Norway
7678
case 'PL': // Poland
7779
case 'CZ': // Czech Republic
7880
case 'SK': // Slovakia
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import Image from 'next/image';
5+
6+
interface NorwayBandProps {
7+
scale?: number;
8+
height?: number | string;
9+
borderRadius?: number;
10+
}
11+
12+
export default function NorwayBand({ scale = 1, height, borderRadius = 5 }: NorwayBandProps) {
13+
const width = 45 * scale;
14+
const defaultHeight = 110 * scale;
15+
const actualHeight = height || defaultHeight;
16+
const radius = borderRadius * scale;
17+
18+
return (
19+
<div
20+
style={{
21+
display: 'flex',
22+
flexDirection: 'column',
23+
alignItems: 'center',
24+
justifyContent: 'center',
25+
gap: `${6 * scale}px`,
26+
width: `${width}px`,
27+
height: actualHeight,
28+
backgroundColor: '#003399', // Blue like EU band
29+
borderRadius: `${radius}px 0 0 ${radius}px`,
30+
padding: `${6 * scale}px ${4 * scale}px`,
31+
}}
32+
>
33+
{/* Norwegian Flag */}
34+
<div style={{
35+
width: `${32 * scale}px`,
36+
height: `${24 * scale}px`,
37+
position: 'relative',
38+
borderRadius: `${2 * scale}px`,
39+
overflow: 'hidden',
40+
boxShadow: `0 ${1 * scale}px ${3 * scale}px rgba(0,0,0,0.4)`,
41+
}}>
42+
<Image
43+
src="/flags/no.svg"
44+
alt="Norwegian Flag"
45+
fill
46+
style={{ objectFit: 'cover' }}
47+
/>
48+
</div>
49+
50+
{/* Country code N */}
51+
<span
52+
style={{
53+
color: '#FFFFFF',
54+
fontSize: `${26 * scale}px`,
55+
fontWeight: 'bold',
56+
fontFamily: 'Arial, sans-serif',
57+
letterSpacing: '1px',
58+
textShadow: `0 ${1 * scale}px ${2 * scale}px rgba(0,0,0,0.3)`,
59+
}}
60+
>
61+
N
62+
</span>
63+
</div>
64+
);
65+
}

src/i18n/translations.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const LANGUAGE_FLAGS: Record<Language, string> = {
3030
};
3131

3232
// Country codes type
33-
export type CountryCode = 'D' | 'A' | 'B' | 'BG' | 'CH' | 'HR' | 'CY' | 'CZ' | 'DK' | 'EST' | 'FIN' | 'F' | 'GB' | 'GR' | 'H' | 'IRL' | 'I' | 'LV' | 'LT' | 'L' | 'M' | 'NL' | 'PL' | 'P' | 'RO' | 'SK' | 'SLO' | 'E' | 'S';
33+
export type CountryCode = 'D' | 'A' | 'B' | 'BG' | 'CH' | 'HR' | 'CY' | 'CZ' | 'DK' | 'EST' | 'FIN' | 'F' | 'GB' | 'GR' | 'H' | 'IRL' | 'I' | 'LV' | 'LT' | 'L' | 'M' | 'N' | 'NL' | 'PL' | 'P' | 'RO' | 'SK' | 'SLO' | 'E' | 'S';
3434

3535
export interface Translations {
3636
// Page title
@@ -151,7 +151,7 @@ const translations: Record<Language, Translations> = {
151151
'F': 'Frankreich', 'GB': 'Vereinigtes Königreich', 'GR': 'Griechenland', 'H': 'Ungarn', 'IRL': 'Irland', 'I': 'Italien',
152152
'LV': 'Lettland', 'LT': 'Litauen', 'L': 'Luxemburg', 'M': 'Malta', 'NL': 'Niederlande',
153153
'PL': 'Polen', 'P': 'Portugal', 'RO': 'Rumänien', 'SK': 'Slowakei', 'SLO': 'Slowenien',
154-
'E': 'Spanien', 'S': 'Schweden',
154+
'E': 'Spanien', 'N': 'Norwegen', 'S': 'Schweden',
155155
},
156156
},
157157
en: {
@@ -202,7 +202,7 @@ const translations: Record<Language, Translations> = {
202202
'F': 'France', 'GB': 'United Kingdom', 'GR': 'Greece', 'H': 'Hungary', 'IRL': 'Ireland', 'I': 'Italy',
203203
'LV': 'Latvia', 'LT': 'Lithuania', 'L': 'Luxembourg', 'M': 'Malta', 'NL': 'Netherlands',
204204
'PL': 'Poland', 'P': 'Portugal', 'RO': 'Romania', 'SK': 'Slovakia', 'SLO': 'Slovenia',
205-
'E': 'Spain', 'S': 'Sweden',
205+
'E': 'Spain', 'N': 'Norway', 'S': 'Sweden',
206206
},
207207
},
208208
fr: {
@@ -253,7 +253,7 @@ const translations: Record<Language, Translations> = {
253253
'F': 'France', 'GB': 'Royaume-Uni', 'GR': 'Grèce', 'H': 'Hongrie', 'IRL': 'Irlande', 'I': 'Italie',
254254
'LV': 'Lettonie', 'LT': 'Lituanie', 'L': 'Luxembourg', 'M': 'Malte', 'NL': 'Pays-Bas',
255255
'PL': 'Pologne', 'P': 'Portugal', 'RO': 'Roumanie', 'SK': 'Slovaquie', 'SLO': 'Slovénie',
256-
'E': 'Espagne', 'S': 'Suède',
256+
'E': 'Espagne', 'N': 'Norvège', 'S': 'Suède',
257257
},
258258
},
259259
es: {
@@ -304,7 +304,7 @@ const translations: Record<Language, Translations> = {
304304
'F': 'Francia', 'GB': 'Reino Unido', 'GR': 'Grecia', 'H': 'Hungría', 'IRL': 'Irlanda', 'I': 'Italia',
305305
'LV': 'Letonia', 'LT': 'Lituania', 'L': 'Luxemburgo', 'M': 'Malta', 'NL': 'Países Bajos',
306306
'PL': 'Polonia', 'P': 'Portugal', 'RO': 'Rumanía', 'SK': 'Eslovaquia', 'SLO': 'Eslovenia',
307-
'E': 'España', 'S': 'Suecia',
307+
'E': 'España', 'N': 'Noruega', 'S': 'Suecia',
308308
},
309309
},
310310
it: {
@@ -355,7 +355,7 @@ const translations: Record<Language, Translations> = {
355355
'F': 'Francia', 'GB': 'Regno Unito', 'GR': 'Grecia', 'H': 'Ungheria', 'IRL': 'Irlanda', 'I': 'Italia',
356356
'LV': 'Lettonia', 'LT': 'Lituania', 'L': 'Lussemburgo', 'M': 'Malta', 'NL': 'Paesi Bassi',
357357
'PL': 'Polonia', 'P': 'Portogallo', 'RO': 'Romania', 'SK': 'Slovacchia', 'SLO': 'Slovenia',
358-
'E': 'Spagna', 'S': 'Svezia',
358+
'E': 'Spagna', 'N': 'Norvegia', 'S': 'Svezia',
359359
},
360360
},
361361
nl: {
@@ -406,7 +406,7 @@ const translations: Record<Language, Translations> = {
406406
'F': 'Frankrijk', 'GB': 'Verenigd Koninkrijk', 'GR': 'Griekenland', 'H': 'Hongarije', 'IRL': 'Ierland', 'I': 'Italië',
407407
'LV': 'Letland', 'LT': 'Litouwen', 'L': 'Luxemburg', 'M': 'Malta', 'NL': 'Nederland',
408408
'PL': 'Polen', 'P': 'Portugal', 'RO': 'Roemenië', 'SK': 'Slowakije', 'SLO': 'Slovenië',
409-
'E': 'Spanje', 'S': 'Zweden',
409+
'E': 'Spanje', 'N': 'Noorwegen', 'S': 'Zweden',
410410
},
411411
},
412412
pl: {
@@ -457,7 +457,7 @@ const translations: Record<Language, Translations> = {
457457
'F': 'Francja', 'GB': 'Wielka Brytania', 'GR': 'Grecja', 'H': 'Węgry', 'IRL': 'Irlandia', 'I': 'Włochy',
458458
'LV': 'Łotwa', 'LT': 'Litwa', 'L': 'Luksemburg', 'M': 'Malta', 'NL': 'Holandia',
459459
'PL': 'Polska', 'P': 'Portugalia', 'RO': 'Rumunia', 'SK': 'Słowacja', 'SLO': 'Słowenia',
460-
'E': 'Hiszpania', 'S': 'Szwecja',
460+
'E': 'Hiszpania', 'N': 'Norwegia', 'S': 'Szwecja',
461461
},
462462
},
463463
pt: {
@@ -508,7 +508,7 @@ const translations: Record<Language, Translations> = {
508508
'F': 'França', 'GB': 'Reino Unido', 'GR': 'Grécia', 'H': 'Hungria', 'IRL': 'Irlanda', 'I': 'Itália',
509509
'LV': 'Letónia', 'LT': 'Lituânia', 'L': 'Luxemburgo', 'M': 'Malta', 'NL': 'Países Baixos',
510510
'PL': 'Polónia', 'P': 'Portugal', 'RO': 'Roménia', 'SK': 'Eslováquia', 'SLO': 'Eslovénia',
511-
'E': 'Espanha', 'S': 'Suécia',
511+
'E': 'Espanha', 'N': 'Noruega', 'S': 'Suécia',
512512
},
513513
},
514514
sv: {
@@ -559,7 +559,7 @@ const translations: Record<Language, Translations> = {
559559
'F': 'Frankrike', 'GB': 'Storbritannien', 'GR': 'Grekland', 'H': 'Ungern', 'IRL': 'Irland', 'I': 'Italien',
560560
'LV': 'Lettland', 'LT': 'Litauen', 'L': 'Luxemburg', 'M': 'Malta', 'NL': 'Nederländerna',
561561
'PL': 'Polen', 'P': 'Portugal', 'RO': 'Rumänien', 'SK': 'Slovakien', 'SLO': 'Slovenien',
562-
'E': 'Spanien', 'S': 'Sverige',
562+
'E': 'Spanien', 'N': 'Norge', 'S': 'Sverige',
563563
},
564564
},
565565
cs: {
@@ -610,7 +610,7 @@ const translations: Record<Language, Translations> = {
610610
'F': 'Francie', 'GB': 'Spojené království', 'GR': 'Řecko', 'H': 'Maďarsko', 'IRL': 'Irsko', 'I': 'Itálie',
611611
'LV': 'Lotyšsko', 'LT': 'Litva', 'L': 'Lucembursko', 'M': 'Malta', 'NL': 'Nizozemsko',
612612
'PL': 'Polsko', 'P': 'Portugalsko', 'RO': 'Rumunsko', 'SK': 'Slovensko', 'SLO': 'Slovinsko',
613-
'E': 'Španělsko', 'S': 'Švédsko',
613+
'E': 'Španělsko', 'N': 'Norsko', 'S': 'Švédsko',
614614
},
615615
},
616616
};

src/types/plate.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export type Country =
4747
| 'SK' // Slovakia
4848
| 'SLO' // Slovenia
4949
| 'E' // Spain
50+
| 'N' // Norway
5051
| 'S'; // Sweden
5152

5253
export const EU_COUNTRY_NAMES: Record<Country, string> = {
@@ -78,6 +79,7 @@ export const EU_COUNTRY_NAMES: Record<Country, string> = {
7879
'SK': 'Slowakei',
7980
'SLO': 'Slowenien',
8081
'E': 'Spanien',
82+
'N': 'Norwegen',
8183
'S': 'Schweden',
8284
};
8385

0 commit comments

Comments
 (0)