feat: translate the page

This commit is contained in:
max_richter 2023-11-29 15:59:16 +01:00
parent 5d1a7e98c1
commit 7cdab9c68b
19 changed files with 542 additions and 88 deletions

5
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"recommendations": [
"inlang.vs-code-extension"
]
}

52
messages/de.json Normal file
View File

@ -0,0 +1,52 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"invite": "Wir laden dich herzlich ein, an unserer exklusiven Silvesterparty teilzunehmen, die dieses Jahr im magischen Ambiente eines Maskenballs stattfindet. Tauche ein in eine Nacht voller Geheimnisse, Eleganz und festlichem Glanz.",
"welcome": "Willkommen zum Maskenball",
"acceptInvite": "Einladung annehmen",
"nameTooLong": "Wir bitten um Entschuldigung, aber dieser Name ist zu lang. (maximal 100 Zeichen)",
"createNameWith": "Wir werden {name} mit",
"wantAlternativePersonality": "Möchtet Ihr, dass wir eine alternative Persönlichkeit für Euch erschaffen?",
"wantNobleName": "Möchtet Ihr einen würdigen Adelsnamen für Euch in Erwägung ziehen?",
"yourNobleName": "Euer Adelsname",
"nobleName":"Adelstitel",
"name": "Name",
"titleTooLong": "Wir bitten um Entschuldigung, aber dieser Titel ist zu lang. (maximal 100 Zeichen)",
"hundredChars": "/100 Zeichen",
"accept": "akzeptieren",
"newSuggestions": "neue vorschläge",
"titleSuggestions": "Adelsname Vorschläge",
"shouldCreatePortrait": "Sollten unsere begabten Künstler ein majestätisches Porträt von Euch anfertigen?",
"skinVeryBright": "sehr heller",
"skinBright": "heller",
"skinMedium": "medium",
"skinDark": "dunkler",
"skinVeryDark": "sehr dunkler",
"skinAnd": "Haut und",
"hairTypeStraight": "glatten",
"hairTypeCurly": "lockigen",
"hairTypeWavy": "welligen",
"hairLengthLong": "langen",
"hairLengthMedium": "medium-langen",
"hairLengthShort": "kurzen",
"hairColorRed": "roten",
"hairColorBlack": "schwarzen",
"hairColorBlond": "blonden",
"hairColorBrown": "braunen",
"hairDrawing": "Haaren zeichnen",
"paintPortrait": "porträt malen (~15 Sekunden)",
"portraitIsBeingDrawn": "Euer edles Antlitz wird gemalt",
"acceptPortrait": "Porträt annehmen",
"requestNewPortrait": "Neues Porträt anfordern",
"invitationIsBeingSend": "Einladung wird abgeschickt",
"sendInvitation": "Einladung versenden",
"guestGallery": "Gallerie der Gäste",
"howSureAppearing": "Wie sicher dürfen wir mit Eurem glanzvollen Erscheinen rechnen?",
"howName": "Wie lauten Euer Vor- und Nachname, edler Gast?",
"saveName": "Name speichern",
"notAtAll": "gar nicht",
"very": "sehr",
"yes": "Ja",
"no": "Nein",
"alreadyHaveOne": "ich habe bereits einen",
"nobleTitlesAreWritten": "Adelsnamen werden geschrieben"
}

52
messages/en.json Normal file
View File

@ -0,0 +1,52 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"invite": "We cordially invite you to take part in our exclusive New Year's Eve party, which this year will take place in the magical ambience of a masked ball. Immerse yourself in a night full of mystery, elegance and festive splendor.",
"welcome": "Welcome to the Masquerade Ball",
"acceptInvite": "Accept invite",
"nameTooLong": "We apologize, but this name is too long. (maximum 100 characters)",
"createNameWith": "We will draw {name} with",
"wantAlternativePersonality": "Would you like us to create an alternative personality for you?",
"wantNobleName": "Would you like to consider a worthy noble name for yourself?",
"yourNobleName": "Your noble name",
"nobleName":"Noble Title",
"name": "Surname",
"titleTooLong": "We apologize, but this title is too long. (maximum 100 characters)",
"hundredChars": "/100 characters",
"accept": "accept",
"newSuggestions": "new suggestions",
"titleSuggestions": "Noble name suggestions",
"shouldCreatePortrait": "Should our talented artists create a majestic portrait of you?",
"skinVeryBright": "very brighter",
"skinBright": "brighter",
"skinMedium": "medium",
"skinDark": "darker",
"skinVeryDark": "very darker",
"skinAnd": "skin and",
"hairTypeStraight": "straight",
"hairTypeCurly": "curly",
"hairTypeWavy": "wavy",
"hairLengthLong": "long",
"hairLengthMedium": "medium-long",
"hairLengthShort": "short",
"hairColorRed": "red",
"hairColorBlack": "black",
"hairColorBlond": "blond",
"hairColorBrown": "brown",
"hairDrawing": "hair",
"paintPortrait": "paint portrait (~15 seconds)",
"portraitIsBeingDrawn": "Your noble face will be painted",
"acceptPortrait": "Accept portrait",
"requestNewPortrait": "Request a new portrait",
"invitationIsBeingSend": "Invitation is sent",
"sendInvitation": "Send invitation",
"guestGallery": "Gallery of guests",
"howSureAppearing": "How confident can we be of your brilliant appearance?",
"howName": "What are your first and last names, noble guest?",
"saveName": "Save name",
"notAtAll": "not at all",
"very": "very",
"yes": "Yes",
"no": "No",
"alreadyHaveOne": "I already have one",
"nobleTitlesAreWritten": "Noble names are written"
}

View File

@ -13,6 +13,8 @@
"compress-s3": "bun ./bin/compress_s3.ts"
},
"devDependencies": {
"@inlang/paraglide-js": "1.0.0-prerelease.12",
"@inlang/paraglide-js-adapter-vite": "1.0.0-prerelease.2",
"@sveltejs/adapter-node": "^1.3.1",
"@sveltejs/kit": "^1.27.5",
"@typescript-eslint/eslint-plugin": "^6.10.0",

View File

@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
googleapis:
specifier: ^128.0.0
@ -18,6 +22,12 @@ dependencies:
version: 0.32.6
devDependencies:
'@inlang/paraglide-js':
specifier: 1.0.0-prerelease.12
version: 1.0.0-prerelease.12
'@inlang/paraglide-js-adapter-vite':
specifier: 1.0.0-prerelease.2
version: 1.0.0-prerelease.2
'@sveltejs/adapter-node':
specifier: ^1.3.1
version: 1.3.1(@sveltejs/kit@1.27.5)
@ -339,6 +349,138 @@ packages:
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
dev: true
/@inlang/json-types@1.1.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-n6vS6AqETsCFbV4TdBvR/EH57waVXzKsMqeUQ+eH2Q6NUATfKhfLabgNms2A+QV3aedH/hLtb1pRmjl2ykBVZg==}
peerDependencies:
'@sinclair/typebox': ^0.31.0
dependencies:
'@sinclair/typebox': 0.31.28
dev: true
/@inlang/language-tag@1.2.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-AwKNPYPgJrhM9ebEYQvcG5PGM4v79jMPlsv2bUYEhEZzMpwIJKQo4t7P7EekMhO086sXOmeTu410Lm8abX/2Yw==}
peerDependencies:
'@sinclair/typebox': ^0.31.0
dependencies:
'@sinclair/typebox': 0.31.28
dev: true
/@inlang/message-lint-rule@1.4.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-imOvpxKFP2ESaWTI5W5aQiW1ukvXMvGa4KhVknssfA1ZkCkVu2EDM4aGxw11U5Rli4QQ70bxztUvfLVhd3J84A==}
peerDependencies:
'@sinclair/typebox': ^0.31.17
dependencies:
'@inlang/json-types': 1.1.0(@sinclair/typebox@0.31.28)
'@inlang/language-tag': 1.2.0(@sinclair/typebox@0.31.28)
'@inlang/message': 2.0.0(@sinclair/typebox@0.31.28)
'@inlang/project-settings': 2.2.0(@sinclair/typebox@0.31.28)
'@inlang/translatable': 1.2.0(@sinclair/typebox@0.31.28)
'@sinclair/typebox': 0.31.28
dev: true
/@inlang/message@2.0.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-RPFcbega2Cnxi78d08O7SbuXyuhEqsB819QjgloNTXWtlBFwVDkF87xAMIZN37hpM6JZzMaYv2O1ipyncU3Ccg==}
peerDependencies:
'@sinclair/typebox': ^0.31.0
dependencies:
'@inlang/language-tag': 1.2.0(@sinclair/typebox@0.31.28)
'@sinclair/typebox': 0.31.28
dev: true
/@inlang/module@1.2.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-Z91zJUgliX+ddfRK+Ce4aZYlMjeNwZJOMmJ2dEUgg2cfqIFRB+gDsC5gLEY5LTkZspf/XUHoECTpK8ErVVYF5w==}
peerDependencies:
'@sinclair/typebox': ^0.31.17
dependencies:
'@inlang/message-lint-rule': 1.4.0(@sinclair/typebox@0.31.28)
'@inlang/plugin': 2.4.0(@sinclair/typebox@0.31.28)
'@sinclair/typebox': 0.31.28
dev: true
/@inlang/paraglide-js-adapter-unplugin@1.0.0-prerelease.2:
resolution: {integrity: sha512-Z2AGwc5zLkZyhDjlD/W17uASttlxalgnMUfT8gcsjBOEHr4h1KV6zJfo8mha0/YQRpSveBPbRhruY+4EQ6CNvA==}
dependencies:
'@inlang/paraglide-js': 1.0.0-prerelease.12
'@inlang/sdk': 0.18.0
kleur: 4.1.5
unplugin: 1.5.1
transitivePeerDependencies:
- babel-plugin-macros
dev: true
/@inlang/paraglide-js-adapter-vite@1.0.0-prerelease.2:
resolution: {integrity: sha512-M1Za1FUlR7wKUnA8wIJkLO+Z0gEr/WU7EJ1KZsmPzJFE7NUuKqYTqgTqumEWGo23p1XJ/cAQOzXNLKYzbqK3Ug==}
dependencies:
'@inlang/paraglide-js-adapter-unplugin': 1.0.0-prerelease.2
transitivePeerDependencies:
- babel-plugin-macros
dev: true
/@inlang/paraglide-js@1.0.0-prerelease.12:
resolution: {integrity: sha512-YOXpLYfG8XgdinF6ZSEB0TQPtvXGQzLTbhxJY7aGBJzt+zmAtqaXpxresw7Hp++7EBd/2DMmMiiuKz6ch3OzrA==}
hasBin: true
dev: true
/@inlang/plugin@2.4.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-4+T7ZfuqcW4GFp3G+Vb+RTlYF8kKPY/BH0BcvOV2HX5B9UzgyC+dpXiI3TRQTUj7vz0yqp4K+onsaehPb2NGvw==}
peerDependencies:
'@sinclair/typebox': ^0.31.17
dependencies:
'@inlang/json-types': 1.1.0(@sinclair/typebox@0.31.28)
'@inlang/language-tag': 1.2.0(@sinclair/typebox@0.31.28)
'@inlang/message': 2.0.0(@sinclair/typebox@0.31.28)
'@inlang/project-settings': 2.2.0(@sinclair/typebox@0.31.28)
'@inlang/translatable': 1.2.0(@sinclair/typebox@0.31.28)
'@lix-js/fs': 0.4.0
'@sinclair/typebox': 0.31.28
dev: true
/@inlang/project-settings@2.2.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-M1D150KYiYoyiHhQp627zhvo/w/M1B11ROEu2u7Jn9005mKEWZS1DDlEOsLuNRl5doHSPHfkGa9qItMtrqr0dA==}
peerDependencies:
'@sinclair/typebox': ^0.31.0
dependencies:
'@inlang/json-types': 1.1.0(@sinclair/typebox@0.31.28)
'@inlang/language-tag': 1.2.0(@sinclair/typebox@0.31.28)
'@sinclair/typebox': 0.31.28
dev: true
/@inlang/result@1.1.0:
resolution: {integrity: sha512-zLGroi9EUiHuOjUOaglUVTFO7EWdo2OARMJLBO1Q5Ga/xJmSQb6XS1lhqEXBFAjgFarfEMX5YEJWWALogYV3wA==}
dev: true
/@inlang/sdk@0.18.0:
resolution: {integrity: sha512-HLZhR+w3gxoSs5sTUFIaSVjX7XPkTCzOzd1/QzdMVlRXucSTXViztJ6UJZ3aULAkuixfnkMSS1WfjE9TA1SOeA==}
engines: {node: '>=18.0.0'}
dependencies:
'@inlang/json-types': 1.1.0(@sinclair/typebox@0.31.28)
'@inlang/language-tag': 1.2.0(@sinclair/typebox@0.31.28)
'@inlang/message': 2.0.0(@sinclair/typebox@0.31.28)
'@inlang/message-lint-rule': 1.4.0(@sinclair/typebox@0.31.28)
'@inlang/module': 1.2.0(@sinclair/typebox@0.31.28)
'@inlang/plugin': 2.4.0(@sinclair/typebox@0.31.28)
'@inlang/project-settings': 2.2.0(@sinclair/typebox@0.31.28)
'@inlang/result': 1.1.0
'@inlang/translatable': 1.2.0(@sinclair/typebox@0.31.28)
'@lix-js/fs': 0.4.0
'@sinclair/typebox': 0.31.28
dedent: 1.5.1
deepmerge-ts: 5.1.0
solid-js: 1.6.12
throttle-debounce: 5.0.0
transitivePeerDependencies:
- babel-plugin-macros
dev: true
/@inlang/translatable@1.2.0(@sinclair/typebox@0.31.28):
resolution: {integrity: sha512-Od/nBm3qigfSpYJKu/Isg0rb34ohZApNk+fOtmZ0vBZXsTBzKaYFW0SeBVqwociRCr1tj40N659Ky+RoyLcv8A==}
peerDependencies:
'@sinclair/typebox': ^0.31.0
dependencies:
'@inlang/language-tag': 1.2.0(@sinclair/typebox@0.31.28)
'@sinclair/typebox': 0.31.28
dev: true
/@jridgewell/gen-mapping@0.3.3:
resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
engines: {node: '>=6.0.0'}
@ -369,6 +511,12 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
/@lix-js/fs@0.4.0:
resolution: {integrity: sha512-IOno98FwY+TPinwXzg5dx6xkCwyBCvkv6DMAQjI1Us4rvI9zObfjXd4E2VIGyT7vfUhpXIs4KXmne+onkCDzsg==}
dependencies:
js-base64: 3.7.5
dev: true
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -458,6 +606,10 @@ packages:
rollup: 3.29.4
dev: true
/@sinclair/typebox@0.31.28:
resolution: {integrity: sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ==}
dev: true
/@sveltejs/adapter-node@1.3.1(@sveltejs/kit@1.27.5):
resolution: {integrity: sha512-A0VgRQDCDPzdLNoiAbcOxGw4zT1Mc+n1LwT1OmO350R7WxrEqdMUChPPOd1iMfIDWlP4ie6E2d/WQf5es2d4Zw==}
peerDependencies:
@ -1019,6 +1171,10 @@ packages:
hasBin: true
dev: true
/csstype@3.1.2:
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
dev: true
/debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
@ -1042,6 +1198,15 @@ packages:
mimic-response: 3.1.0
dev: false
/dedent@1.5.1:
resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==}
peerDependencies:
babel-plugin-macros: ^3.1.0
peerDependenciesMeta:
babel-plugin-macros:
optional: true
dev: true
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
@ -1051,6 +1216,11 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
/deepmerge-ts@5.1.0:
resolution: {integrity: sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw==}
engines: {node: '>=16.0.0'}
dev: true
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
@ -1819,6 +1989,10 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/js-base64@3.7.5:
resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==}
dev: true
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@ -2506,6 +2680,12 @@ packages:
engines: {node: '>=8'}
dev: true
/solid-js@1.6.12:
resolution: {integrity: sha512-JFqRobfG3q5r1l4RYVOAukk6+FWtHpXGIjgh/GEsHKweN/kK+iHOtzUALE6+P5t/jIcSNeGiVitX8gmJg+cYvQ==}
dependencies:
csstype: 3.1.2
dev: true
/sorcery@0.11.0:
resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==}
hasBin: true
@ -2744,6 +2924,11 @@ packages:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
/throttle-debounce@5.0.0:
resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==}
engines: {node: '>=12.22'}
dev: true
/through2@4.0.2:
resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==}
dependencies:
@ -2821,6 +3006,15 @@ packages:
'@fastify/busboy': 2.0.0
dev: true
/unplugin@1.5.1:
resolution: {integrity: sha512-0QkvG13z6RD+1L1FoibQqnvTwVBXvS4XSPwAyinVgoOCl2jAgwzdUKmEj05o4Lt8xwQI85Hb6mSyYkcAGwZPew==}
dependencies:
acorn: 8.11.2
chokidar: 3.5.3
webpack-sources: 3.2.3
webpack-virtual-modules: 0.6.1
dev: true
/uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
@ -2917,6 +3111,15 @@ packages:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
dev: false
/webpack-sources@3.2.3:
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
engines: {node: '>=10.13.0'}
dev: true
/webpack-virtual-modules@0.6.1:
resolution: {integrity: sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==}
dev: true
/whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
dependencies:
@ -2975,7 +3178,3 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false

19
project.inlang.json Normal file
View File

@ -0,0 +1,19 @@
{
"$schema": "https://inlang.com/schema/project-settings",
"sourceLanguageTag": "de",
"languageTags": [
"en",
"de"
],
"modules": [
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@latest/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@latest/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@latest/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@latest/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@latest/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@latest/dist/index.js"
],
"plugin.inlang.messageFormat": {
"pathPattern": "./messages/{languageTag}.json"
}
}

View File

@ -1,4 +1,5 @@
<script lang="ts">
import * as m from '$paraglide/messages';
export let min = 0;
export let max = 100;
export let value = 50;
@ -6,8 +7,8 @@
<div class="wrapper">
<input type="range" {min} {max} bind:value step={10} />
<p class="left">gar nicht</p>
<p class="right">sehr</p>
<p class="left">{m.notAtAll()}</p>
<p class="right">{m.very()}</p>
</div>
<style>

View File

@ -0,0 +1,81 @@
<script lang="ts">
import {
availableLanguageTags,
setLanguageTag,
onSetLanguageTag,
sourceLanguageTag,
languageTag
} from '$paraglide/runtime';
import { getContext, setContext } from 'svelte';
import { page } from '$app/stores';
import { redirect } from '@sveltejs/kit';
// We check if the language tag is valid, if it is, we set it,
// if not, we redirect to the same page without the language tag
setContext(
'languageTag',
$page.params.lang
? (availableLanguageTags as readonly string[]).includes($page.params.lang)
? $page.params.lang
: (() => {
throw redirect(
302,
('/' + $page.url.href.split($page.params.lang)[1]).replace('//', '/')
);
})()
: sourceLanguageTag
);
setLanguageTag(() => getContext('languageTag'));
// We save the old language tag to check if the language tag has changed
let oldLanguageTag = languageTag();
if (import.meta.env.SSR === false) {
onSetLanguageTag((newLanguageTag) => {
// If the language tag is the same as the current language tag, we don't want to do anything
if (newLanguageTag === oldLanguageTag) return;
// If we set the language tag to the source language tag, we want to remove the language tag from the url
if (newLanguageTag === sourceLanguageTag) {
// this returns the route without the language tag
const route = window.location.href.match(/^https?:\/\/[^\/]+\/[^\/]*(\/.*)/);
// Redirect to the same page with the new language
window.location.href = route ? route[1] : '/';
// renew the old language tag
oldLanguageTag = newLanguageTag;
// if we set the language tag from the source language tag, we want to add the language tag to the url
} else if (oldLanguageTag === sourceLanguageTag) {
// this simply returns the route, since we don't have to remove the language tag,
// beacuse the preveous language was the source language.
// It also does not matter if for some reason "en" language tag is still given, it removes it anyway.
const route = window.location.href
.replace(/^https?:\/\/[^\/]+\/(en)(\/|$)/, '')
.match(/^https?:\/\/[^\/]+(\/.*)/);
// Redirect to the same page with the new language
window.location.href = route ? '/' + newLanguageTag + route[1] : '/' + newLanguageTag;
// renew the old language tag
oldLanguageTag = newLanguageTag;
// if we change the language tag not from and not to the source language, we want to keep the url
} else {
// this returns the route without the language tag
const route = window.location.href.match(/^https?:\/\/[^\/]+\/[^\/]*(\/.*)/);
// Redirect to the same page with the new language
window.location.href =
route && route[1] ? '/' + newLanguageTag + route[1] : '/' + newLanguageTag;
// renew the old language tag
oldLanguageTag = newLanguageTag;
}
});
}
</script>
<slot />

View File

@ -7,6 +7,7 @@
import InputRange from './InputRange.svelte';
import { goto } from '$app/navigation';
import Loader from './Loader.svelte';
import * as m from '$paraglide/messages';
let data = persisted<{
name: string;
@ -104,32 +105,29 @@
<div class="wrapper">
<section in:slide={{ delay: 500 }}>
<TextSplit content="Wie lauten Euer Vor- und Nachname, edler Gast?" />
<TextSplit content={m.howName()} />
<input placeholder="Name" type="text" bind:value={$data.name} />
{#if $data.name.length > 99}
<p class="error">
Wir bitten um Entschuldigung, aber dieser Name ist zu lang. (maximal 100 Zeichen)
{m.nameTooLong()}
</p>
{:else if $data.showNameLengthError}
<p class="hint">{$data.name.length}/100 Zeichen</p>
<p class="hint">{$data.name.length}{m.hundredChars()}</p>
{/if}
{#if !$data.nameAccepted}
<button
disabled={$data.name.length > 99}
on:click={() => {
$data.nameAccepted = true;
}}>Name speichern</button
}}>{m.saveName()}</button
>
{/if}
</section>
{#if ($data.name && $data.nameAccepted) || $data.confidence !== undefined}
<section in:slide={{ delay: 0, duration: 500 }}>
<TextSplit
content="Wie sicher dürfen wir mit Eurem glanzvollen Erscheinen rechnen?"
delay={0}
/>
<TextSplit content={m.howSureAppearing()} delay={0} />
<div in:fade={{ delay: 1200 }}>
<InputRange bind:value={$data.confidence} />
</div>
@ -145,19 +143,17 @@
{#if $data.confidence !== undefined && $data.confidenceAccepted && $data.createPersonality === undefined}
<section in:slide out:slide>
<TextSplit
content="Möchtet Ihr, dass wir eine alternative Persönlichkeit für Euch erschaffen?"
/>
<TextSplit content={m.wantAlternativePersonality()} />
<div>
<button
on:click={() => {
$data.createPersonality = true;
}}>Ja</button
}}>{m.yes()}</button
>
<button
on:click={() => {
$data.createPersonality = false;
}}>Nein</button
}}>{m.no()}</button
>
</div>
{#if $data.adelsTitel}
@ -169,7 +165,7 @@
{#if $data.createPersonality === true}
<section in:fade out:slide>
{#if $data.provideAdelsTitel === undefined}
<TextSplit content="Möchtet Ihr einen würdigen Adelsnamen für Euch in Erwägung ziehen?" />
<TextSplit content={m.wantNobleName()} />
<div>
<button
on:click={() => {
@ -177,7 +173,7 @@
$data.provideAdelsTitel = true;
}}
>
ja</button
{m.yes()}</button
>
<button
on:click={() => {
@ -185,7 +181,7 @@
$data.provideAdelsTitel = true;
}}
>
ich habe bereits einen
{m.alreadyHaveOne()}
</button>
<button
on:click={() => {
@ -193,7 +189,7 @@
$data.provideAdelsTitel = false;
}}
>
nein</button
{m.no()}</button
>
</div>
{/if}
@ -201,34 +197,34 @@
{#if loadingAdelsTitel}
<div style="display: flex; gap: 20px; align-items: center;">
<Loader />
<p>Adelsnamen werden geschrieben</p>
<p>{m.nobleTitlesAreWritten()}</p>
</div>
{:else if typeof $data.adelsTitel === 'string'}
<TextSplit content="Euer Adelsname" />
<input placeholder="Name" type="text" bind:value={$data.adelsTitel} />
<TextSplit content={m.yourNobleName()} />
<input placeholder={m.nobleName()} type="text" bind:value={$data.adelsTitel} />
{#if $data.adelsTitel.length > 98}
<p class="error">
Wir bitten um Entschuldigung, aber dieser Titel ist zu lang. (maximal 100 Zeichen)
{m.titleTooLong()}
</p>
{:else if $data.showAdelsTitelLengthError}
<p class="hint">{$data.adelsTitel.length}/100 Zeichen</p>
<p class="hint">{$data.adelsTitel.length}{m.hundredChars()}</p>
{/if}
{#if !$data.adelsTitelAccepted}
<button
disabled={$data.adelsTitel.length > 99}
on:click={() => {
$data.adelsTitelAccepted = true;
}}>akzeptieren</button
}}>{m.accept()}</button
>
<button
on:click={() => {
$data.adelsTitel = undefined;
fetchAdelsTitel();
}}>neue vorschläge</button
}}>{m.newSuggestions()}</button
>
{/if}
{:else if $data.adelsTitelSuggestions?.length}
<p>Adelsname Vorschläge</p>
<p>{m.titleSuggestions()}</p>
<hr />
{#each $data.adelsTitelSuggestions as suggestion}
<button
@ -241,7 +237,7 @@
<button
on:click={() => {
fetchAdelsTitel();
}}>neue vorschläge</button
}}>{m.newSuggestions()}</button
>
{/if}
</section>
@ -250,56 +246,55 @@
{#if $data.adelsTitel && $data.adelsTitelAccepted && $data.providePortrait !== false}
<section transition:slide class="portrait-frame" class:loaded={!!$data.portraitUrl}>
{#if $data.providePortrait === undefined}
<TextSplit
content="Sollten unsere begabten Künstler ein majestätisches Porträt von Euch anfertigen?"
/>
<TextSplit content={m.shouldCreatePortrait()} />
<div>
<button
on:click={() => {
$data.providePortrait = true;
}}>ja</button
}}>{m.yes()}</button
>
<button
on:click={() => {
$data.providePortrait = true;
}}>false</button
}}>{m.no()}</button
>
</div>
{/if}
{#if $data.providePortrait && !loadingPortrait && !$data.portraitUrl}
<p>
Wir werden {$data.adelsTitel || $data.name} mit
{m.createNameWith({ name: $data.adelsTitel || $data.name })}
<select placeholder="Typ" bind:value={$data.portraitSkinColor}>
<option value="very light">sehr heller</option>
<option value="light">heller</option>
<option value="medium">medium</option>
<option value="dark">dunkler</option>
<option value="very dark">sehr dunkler</option>
<option value="very light">{m.skinVeryBright()}</option>
<option value="light">{m.skinBright()}</option>
<option value="medium">{m.skinMedium()}</option>
<option value="dark">{m.skinDark()}</option>
<option value="very dark">{m.skinVeryDark()}</option>
</select>
Haut und
{m.skinAnd()}
<select placeholder="Typ" bind:value={$data.portraitHairType}>
<option value="straight">glatten</option>
<option value="curly">lockigen</option>
<option value="wavy">welligen</option>
<option value="straight">{m.hairTypeStraight()}</option>
<option value="curly">{m.hairTypeCurly()}</option>
<option value="wavy">{m.hairTypeWavy()}</option>
</select>
<select placeholder="Länge" bind:value={$data.portraitHairLength}>
<option value="long">langen</option>
<option value="medium">medium-langen</option>
<option value="short">kurzen</option>
<option value="long">{m.hairLengthLong()}</option>
<option value="medium">{m.hairLengthMedium()}</option>
<option value="short">{m.hairLengthShort()}</option>
</select>,
<select placeholder="Farbe" bind:value={$data.portraitHairColor}>
<option value="red">roten</option>
<option value="black">schwarzen</option>
<option value="blond">blonden</option>
<option value="brown">braunen</option>
</select> Haaren zeichnen
<option value="red">{m.hairColorRed()}</option>
<option value="black">{m.hairColorBlack()}</option>
<option value="blond">{m.hairColorBlond()}</option>
<option value="brown">{m.hairColorBrown()}</option>
</select>
{m.hairDrawing()}
</p>
<button on:click={() => fetchPortrait()}> porträt malen (~15 Sekunden)</button>
<button on:click={() => fetchPortrait()}> {m.paintPortrait()}</button>
{:else if loadingPortrait}
<div style="display: flex; gap: 20px; align-items: center;">
<Loader />
<p>Euer edles Antlitz wird gemalt</p>
<p>{m.portraitIsBeingDrawn()}</p>
</div>
{:else if $data.portraitUrl}
<div in:slide={{ duration: 2000 }} class="portrait">
@ -309,12 +304,12 @@
<button
on:click={() => {
$data.portraitAccepted = true;
}}>Porträt annehmen</button
}}>{m.acceptPortrait()}</button
>
<button
on:click={() => {
$data.portraitUrl = undefined;
}}>Neues Porträt anfordern</button
}}>{m.requestNewPortrait()}</button
>
{/if}
</div>
@ -327,12 +322,12 @@
<section in:slide style="border: none;">
<div style="display: flex; gap: 20px; align-items: center;">
<Loader />
<p>Einladung wird abgeschickt</p>
<p>{m.invitationIsBeingSend()}</p>
</div>
</section>
{:else}
<div class="button-wrapper">
<Button on:click={() => submit()}>Einladung versenden</Button>
<Button on:click={() => submit()}>{m.sendInvitation()}</Button>
</div>
{/if}
{/if}

View File

@ -1,7 +1,8 @@
<script lang="ts">
import * as m from '$paraglide/messages';
</script>
<p>Willkommen zum Maskenball</p>
<p>{m.welcome()}</p>
<style>
p {

View File

@ -0,0 +1,27 @@
import type { LayoutServerLoad } from "./$types";
import { availableLanguageTags } from "$paraglide/runtime";
import { redirect } from "@sveltejs/kit";
type AvailableLanguages = typeof availableLanguageTags[number];
export const load: LayoutServerLoad = function ({ request, cookies }) {
const url = new URL(request.url);
let language = cookies.get("lang") as unknown as AvailableLanguages;
const acceptLanguage = request.headers.get('accept-language')?.split(",")?.[0]?.split("-")?.[0] as AvailableLanguages;
if (!language || !availableLanguageTags.includes(language)) {
if (availableLanguageTags.includes(acceptLanguage)) {
language = acceptLanguage;
cookies.set("lang", language);
} else {
language = "de"
}
}
if (!url.pathname.startsWith("/" + language) && language !== "de") {
throw redirect(302, `/${language}/${url.pathname}`.replaceAll("//", "/"))
}
return
}

View File

@ -1,5 +1,8 @@
<script lang="ts">
import ParaglideAdapter from '$lib/components/ParaglideAdapter.svelte';
import './global.css';
</script>
<slot />
<ParaglideAdapter>
<slot />
</ParaglideAdapter>

View File

@ -1,5 +1,4 @@
<script lang="ts">
import Loader from '$lib/components/Loader.svelte';
import Questions from '$lib/components/Questions.svelte';
import TextSplit from '$lib/components/TextSplit.svelte';
import Button from '$lib/components/button.svelte';
@ -9,6 +8,7 @@
import Maskenball from '$lib/components/maskenball.svelte';
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';
import * as m from '$paraglide/messages';
let curtainsVisible = false;
let buttonVisible = false;
@ -59,10 +59,7 @@
{#if contentVisible}
<div class="einladung" out:fade>
<TextSplit
center
content="Wir laden dich herzlich ein, an unserer exklusiven Silvesterparty teilzunehmen, die dieses Jahr im magischen Ambiente eines Maskenballs stattfindet. Tauche ein in eine Nacht voller Geheimnisse, Eleganz und festlichem Glanz."
/>
<TextSplit center content={m.invite()} />
<span in:fade={{ delay: 8000, duration: 1000 }}>
<Button
@ -70,7 +67,7 @@
on:click={() => {
contentVisible = false;
questionVisible = true;
}}>Einladung annehmen</Button
}}>{m.acceptInvite()}</Button
>
</span>
</div>

View File

@ -2,6 +2,7 @@
import ImageFrame from '$lib/components/ImageFrame.svelte';
import Confetti from '$lib/components/confetti.svelte';
import { onMount } from 'svelte';
import * as m from '$paraglide/messages';
export let data;
@ -29,7 +30,7 @@
</svelte:head>
<div class="wrapper">
<h1>Gallerie der Gäste</h1>
<h1>{m.guestGallery()}</h1>
<div class="grid">
{#each items as item}
<div

3
src/routes/load.ts Normal file
View File

@ -0,0 +1,3 @@
export const load: Handler = async (req, res) => {
};

View File

@ -11,8 +11,11 @@ const config = {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
adapter: adapter(),
alias: {
$paraglide: "./src/paraglide",
},
},
};
export default config;

View File

@ -1,17 +1,18 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "Bundler",
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

View File

@ -1,6 +1,18 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { paraglide } from "@inlang/paraglide-js-adapter-vite"
import path from "path"
export default defineConfig({
plugins: [sveltekit()]
plugins: [sveltekit(), paraglide({
project: "./project.inlang.json",
outdir: "./src/paraglide"
})],
resolve: {
alias: {
// This is the alias you can use in your code
// you can change it to whatever you want
"$paraglide": path.resolve(__dirname, "src/paraglide")
}
}
});