aboutsummaryrefslogtreecommitdiffstats
path: root/code/app/src/i18n
diff options
context:
space:
mode:
Diffstat (limited to 'code/app/src/i18n')
-rw-r--r--code/app/src/i18n/en/app/index.ts7
-rw-r--r--code/app/src/i18n/en/index.ts63
-rw-r--r--code/app/src/i18n/formatters.ts13
-rw-r--r--code/app/src/i18n/i18n-svelte.ts12
-rw-r--r--code/app/src/i18n/i18n-types.ts461
-rw-r--r--code/app/src/i18n/i18n-util.async.ts42
-rw-r--r--code/app/src/i18n/i18n-util.sync.ts35
-rw-r--r--code/app/src/i18n/i18n-util.ts45
-rw-r--r--code/app/src/i18n/nb/app/index.ts7
-rw-r--r--code/app/src/i18n/nb/index.ts51
10 files changed, 736 insertions, 0 deletions
diff --git a/code/app/src/i18n/en/app/index.ts b/code/app/src/i18n/en/app/index.ts
new file mode 100644
index 0000000..7ccfc97
--- /dev/null
+++ b/code/app/src/i18n/en/app/index.ts
@@ -0,0 +1,7 @@
+import type { BaseTranslation } from '../../i18n-types'
+
+const en_app: BaseTranslation = {
+ members: "Members",
+}
+
+export default en_app \ No newline at end of file
diff --git a/code/app/src/i18n/en/index.ts b/code/app/src/i18n/en/index.ts
new file mode 100644
index 0000000..b38eb48
--- /dev/null
+++ b/code/app/src/i18n/en/index.ts
@@ -0,0 +1,63 @@
+import type { BaseTranslation } from "../i18n-types";
+
+const en: BaseTranslation = {
+ or: "Or",
+ name: "Name",
+ emailAddress: "Email address",
+ password: "Password",
+ pageNotFound: "Page not found",
+ noInternet: "It seems like your device does not have a internet connection, please check your connection.",
+ reset: "Reset",
+ of: "{0} of {1}",
+ isRequired: "{0} is required",
+ submit: "Submit",
+ success: "Success",
+ tryAgainSoon: "Try again soon",
+ createANewAccount: "Create a new account",
+ unexpectedError: "An unexpected error occured",
+ notFound: "Not found",
+ documentation: "Documentation",
+ tos: "Terms of service",
+ privacyPolicy: "Privacy policy",
+ signIntoYourAccount: "Sign into your account",
+ combobox: {
+ search: "Search",
+ noRecordsFound: "No records found",
+ createRecordHelpText: "Create a record by typing the name in the search bar and pressing enter",
+ createRecordButtonText: "Press enter or click here to create {0}"
+ },
+ signInPage: {
+ title: "Sign in",
+ notMyComputer: "This is not my computer",
+ resetPassword: "Reset password",
+ yourPasswordIsUpdated: "Your password is updated",
+ signIn: "Sign In",
+ yourNewPasswordIsApplied: "Your new password is applied",
+ signInBelow: "Sign in below",
+ yourAccountIsDisabled: "Your account is disabled",
+ contactYourAdminIfDisabled: "Contact your administrator if this feels wrong",
+ youHaveReachedInactivityLimit: "You've reached the hidden inactivity limit",
+ feelFreeToSignInAgain: "Feel free to sign in again"
+ },
+ signUpPage: {
+ title: "Sign up",
+ createYourNewAccount: "Create your new account",
+ },
+ resetPasswordPage: {
+ title: "Reset password",
+ fulfillTitle: "Set new password",
+ setANewPassword: "Set a new password",
+ expired: "Expired",
+ requestHasExpired: "Your request has expired",
+ requestANewReset: "Request a new reset",
+ invalidRequestTitle: "Your request is invalid",
+ invalidRequestMessage: "This could be due to it being expired, nonexsistent or something else",
+ newPassword: "New password",
+ requestSentMessage: "If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account.",
+ requestAPasswordReset: "Request a password reset",
+ requestNotFound: "Your request was not found",
+ submitANewRequestBelow: "Submit a new reset request below"
+ }
+};
+
+export default en;
diff --git a/code/app/src/i18n/formatters.ts b/code/app/src/i18n/formatters.ts
new file mode 100644
index 0000000..ade2f89
--- /dev/null
+++ b/code/app/src/i18n/formatters.ts
@@ -0,0 +1,13 @@
+import { capitalise } from "$utilities/misc-helpers";
+import type { FormattersInitializer } from "typesafe-i18n";
+import type { Locales, Formatters } from "./i18n-types";
+
+export const initFormatters: FormattersInitializer<Locales, Formatters> = (locale: Locales) => {
+
+ const formatters: Formatters = {
+ // add your formatter functions here
+ capitalise: (value: string) => capitalise(value),
+ };
+
+ return formatters;
+};
diff --git a/code/app/src/i18n/i18n-svelte.ts b/code/app/src/i18n/i18n-svelte.ts
new file mode 100644
index 0000000..6cdffb3
--- /dev/null
+++ b/code/app/src/i18n/i18n-svelte.ts
@@ -0,0 +1,12 @@
+// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten.
+/* eslint-disable */
+
+import { initI18nSvelte } from 'typesafe-i18n/svelte'
+import type { Formatters, Locales, TranslationFunctions, Translations } from './i18n-types'
+import { loadedFormatters, loadedLocales } from './i18n-util'
+
+const { locale, LL, setLocale } = initI18nSvelte<Locales, Translations, TranslationFunctions, Formatters>(loadedLocales, loadedFormatters)
+
+export { locale, LL, setLocale }
+
+export default LL
diff --git a/code/app/src/i18n/i18n-types.ts b/code/app/src/i18n/i18n-types.ts
new file mode 100644
index 0000000..ef1d664
--- /dev/null
+++ b/code/app/src/i18n/i18n-types.ts
@@ -0,0 +1,461 @@
+// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten.
+/* eslint-disable */
+import type { BaseTranslation as BaseTranslationType, LocalizedString, RequiredParams } from 'typesafe-i18n'
+
+export type BaseTranslation = BaseTranslationType & DisallowNamespaces
+export type BaseLocale = 'en'
+
+export type Locales =
+ | 'en'
+ | 'nb'
+
+export type Translation = RootTranslation & DisallowNamespaces
+
+export type Translations = RootTranslation &
+{
+ app: NamespaceAppTranslation
+}
+
+type RootTranslation = {
+ /**
+ * O​r
+ */
+ or: string
+ /**
+ * N​a​m​e
+ */
+ name: string
+ /**
+ * E​m​a​i​l​ ​a​d​d​r​e​s​s
+ */
+ emailAddress: string
+ /**
+ * P​a​s​s​w​o​r​d
+ */
+ password: string
+ /**
+ * P​a​g​e​ ​n​o​t​ ​f​o​u​n​d
+ */
+ pageNotFound: string
+ /**
+ * I​t​ ​s​e​e​m​s​ ​l​i​k​e​ ​y​o​u​r​ ​d​e​v​i​c​e​ ​d​o​e​s​ ​n​o​t​ ​h​a​v​e​ ​a​ ​i​n​t​e​r​n​e​t​ ​c​o​n​n​e​c​t​i​o​n​,​ ​p​l​e​a​s​e​ ​c​h​e​c​k​ ​y​o​u​r​ ​c​o​n​n​e​c​t​i​o​n​.
+ */
+ noInternet: string
+ /**
+ * R​e​s​e​t
+ */
+ reset: string
+ /**
+ * {​0​}​ ​o​f​ ​{​1​}
+ * @param {unknown} 0
+ * @param {unknown} 1
+ */
+ of: RequiredParams<'0' | '1'>
+ /**
+ * {​0​}​ ​i​s​ ​r​e​q​u​i​r​e​d
+ * @param {unknown} 0
+ */
+ isRequired: RequiredParams<'0'>
+ /**
+ * S​u​b​m​i​t
+ */
+ submit: string
+ /**
+ * S​u​c​c​e​s​s
+ */
+ success: string
+ /**
+ * T​r​y​ ​a​g​a​i​n​ ​s​o​o​n
+ */
+ tryAgainSoon: string
+ /**
+ * C​r​e​a​t​e​ ​a​ ​n​e​w​ ​a​c​c​o​u​n​t
+ */
+ createANewAccount: string
+ /**
+ * A​n​ ​u​n​e​x​p​e​c​t​e​d​ ​e​r​r​o​r​ ​o​c​c​u​r​e​d
+ */
+ unexpectedError: string
+ /**
+ * N​o​t​ ​f​o​u​n​d
+ */
+ notFound: string
+ /**
+ * D​o​c​u​m​e​n​t​a​t​i​o​n
+ */
+ documentation: string
+ /**
+ * T​e​r​m​s​ ​o​f​ ​s​e​r​v​i​c​e
+ */
+ tos: string
+ /**
+ * P​r​i​v​a​c​y​ ​p​o​l​i​c​y
+ */
+ privacyPolicy: string
+ /**
+ * S​i​g​n​ ​i​n​t​o​ ​y​o​u​r​ ​a​c​c​o​u​n​t
+ */
+ signIntoYourAccount: string
+ combobox: {
+ /**
+ * S​e​a​r​c​h
+ */
+ search: string
+ /**
+ * N​o​ ​r​e​c​o​r​d​s​ ​f​o​u​n​d
+ */
+ noRecordsFound: string
+ /**
+ * C​r​e​a​t​e​ ​a​ ​r​e​c​o​r​d​ ​b​y​ ​t​y​p​i​n​g​ ​t​h​e​ ​n​a​m​e​ ​i​n​ ​t​h​e​ ​s​e​a​r​c​h​ ​b​a​r​ ​a​n​d​ ​p​r​e​s​s​i​n​g​ ​e​n​t​e​r
+ */
+ createRecordHelpText: string
+ /**
+ * P​r​e​s​s​ ​e​n​t​e​r​ ​o​r​ ​c​l​i​c​k​ ​h​e​r​e​ ​t​o​ ​c​r​e​a​t​e​ ​{​0​}
+ * @param {unknown} 0
+ */
+ createRecordButtonText: RequiredParams<'0'>
+ }
+ signInPage: {
+ /**
+ * S​i​g​n​ ​i​n
+ */
+ title: string
+ /**
+ * T​h​i​s​ ​i​s​ ​n​o​t​ ​m​y​ ​c​o​m​p​u​t​e​r
+ */
+ notMyComputer: string
+ /**
+ * R​e​s​e​t​ ​p​a​s​s​w​o​r​d
+ */
+ resetPassword: string
+ /**
+ * Y​o​u​r​ ​p​a​s​s​w​o​r​d​ ​i​s​ ​u​p​d​a​t​e​d
+ */
+ yourPasswordIsUpdated: string
+ /**
+ * S​i​g​n​ ​I​n
+ */
+ signIn: string
+ /**
+ * Y​o​u​r​ ​n​e​w​ ​p​a​s​s​w​o​r​d​ ​i​s​ ​a​p​p​l​i​e​d
+ */
+ yourNewPasswordIsApplied: string
+ /**
+ * S​i​g​n​ ​i​n​ ​b​e​l​o​w
+ */
+ signInBelow: string
+ /**
+ * Y​o​u​r​ ​a​c​c​o​u​n​t​ ​i​s​ ​d​i​s​a​b​l​e​d
+ */
+ yourAccountIsDisabled: string
+ /**
+ * C​o​n​t​a​c​t​ ​y​o​u​r​ ​a​d​m​i​n​i​s​t​r​a​t​o​r​ ​i​f​ ​t​h​i​s​ ​f​e​e​l​s​ ​w​r​o​n​g
+ */
+ contactYourAdminIfDisabled: string
+ /**
+ * Y​o​u​'​v​e​ ​r​e​a​c​h​e​d​ ​t​h​e​ ​h​i​d​d​e​n​ ​i​n​a​c​t​i​v​i​t​y​ ​l​i​m​i​t
+ */
+ youHaveReachedInactivityLimit: string
+ /**
+ * F​e​e​l​ ​f​r​e​e​ ​t​o​ ​s​i​g​n​ ​i​n​ ​a​g​a​i​n
+ */
+ feelFreeToSignInAgain: string
+ }
+ signUpPage: {
+ /**
+ * S​i​g​n​ ​u​p
+ */
+ title: string
+ /**
+ * C​r​e​a​t​e​ ​y​o​u​r​ ​n​e​w​ ​a​c​c​o​u​n​t
+ */
+ createYourNewAccount: string
+ }
+ resetPasswordPage: {
+ /**
+ * R​e​s​e​t​ ​p​a​s​s​w​o​r​d
+ */
+ title: string
+ /**
+ * S​e​t​ ​n​e​w​ ​p​a​s​s​w​o​r​d
+ */
+ fulfillTitle: string
+ /**
+ * S​e​t​ ​a​ ​n​e​w​ ​p​a​s​s​w​o​r​d
+ */
+ setANewPassword: string
+ /**
+ * E​x​p​i​r​e​d
+ */
+ expired: string
+ /**
+ * Y​o​u​r​ ​r​e​q​u​e​s​t​ ​h​a​s​ ​e​x​p​i​r​e​d
+ */
+ requestHasExpired: string
+ /**
+ * R​e​q​u​e​s​t​ ​a​ ​n​e​w​ ​r​e​s​e​t
+ */
+ requestANewReset: string
+ /**
+ * Y​o​u​r​ ​r​e​q​u​e​s​t​ ​i​s​ ​i​n​v​a​l​i​d
+ */
+ invalidRequestTitle: string
+ /**
+ * T​h​i​s​ ​c​o​u​l​d​ ​b​e​ ​d​u​e​ ​t​o​ ​i​t​ ​b​e​i​n​g​ ​e​x​p​i​r​e​d​,​ ​n​o​n​e​x​s​i​s​t​e​n​t​ ​o​r​ ​s​o​m​e​t​h​i​n​g​ ​e​l​s​e
+ */
+ invalidRequestMessage: string
+ /**
+ * N​e​w​ ​p​a​s​s​w​o​r​d
+ */
+ newPassword: string
+ /**
+ * I​f​ ​w​e​ ​f​i​n​d​ ​y​o​u​r​ ​e​m​a​i​l​ ​a​d​d​r​e​s​s​ ​i​n​ ​o​u​r​ ​s​y​s​t​e​m​s​,​ ​y​o​u​ ​w​i​l​l​ ​r​e​c​e​i​v​e​ ​a​n​ ​e​m​a​i​l​ ​w​i​t​h​ ​i​n​s​t​r​u​c​t​i​o​n​s​ ​o​n​ ​h​o​w​ ​t​o​ ​s​e​t​ ​a​ ​n​e​w​ ​p​a​s​s​w​o​r​d​ ​f​o​r​ ​y​o​u​r​ ​a​c​c​o​u​n​t​.
+ */
+ requestSentMessage: string
+ /**
+ * R​e​q​u​e​s​t​ ​a​ ​p​a​s​s​w​o​r​d​ ​r​e​s​e​t
+ */
+ requestAPasswordReset: string
+ /**
+ * Y​o​u​r​ ​r​e​q​u​e​s​t​ ​w​a​s​ ​n​o​t​ ​f​o​u​n​d
+ */
+ requestNotFound: string
+ /**
+ * S​u​b​m​i​t​ ​a​ ​n​e​w​ ​r​e​s​e​t​ ​r​e​q​u​e​s​t​ ​b​e​l​o​w
+ */
+ submitANewRequestBelow: string
+ }
+}
+
+export type NamespaceAppTranslation = {
+ /**
+ * M​e​m​b​e​r​s
+ */
+ members: string
+}
+
+export type Namespaces =
+ | 'app'
+
+type DisallowNamespaces = {
+ /**
+ * reserved for 'app'-namespace\
+ * you need to use the `./app/index.ts` file instead
+ */
+ app?: "[typesafe-i18n] reserved for 'app'-namespace. You need to use the `./app/index.ts` file instead."
+}
+
+export type TranslationFunctions = {
+ /**
+ * Or
+ */
+ or: () => LocalizedString
+ /**
+ * Name
+ */
+ name: () => LocalizedString
+ /**
+ * Email address
+ */
+ emailAddress: () => LocalizedString
+ /**
+ * Password
+ */
+ password: () => LocalizedString
+ /**
+ * Page not found
+ */
+ pageNotFound: () => LocalizedString
+ /**
+ * It seems like your device does not have a internet connection, please check your connection.
+ */
+ noInternet: () => LocalizedString
+ /**
+ * Reset
+ */
+ reset: () => LocalizedString
+ /**
+ * {0} of {1}
+ */
+ of: (arg0: unknown, arg1: unknown) => LocalizedString
+ /**
+ * {0} is required
+ */
+ isRequired: (arg0: unknown) => LocalizedString
+ /**
+ * Submit
+ */
+ submit: () => LocalizedString
+ /**
+ * Success
+ */
+ success: () => LocalizedString
+ /**
+ * Try again soon
+ */
+ tryAgainSoon: () => LocalizedString
+ /**
+ * Create a new account
+ */
+ createANewAccount: () => LocalizedString
+ /**
+ * An unexpected error occured
+ */
+ unexpectedError: () => LocalizedString
+ /**
+ * Not found
+ */
+ notFound: () => LocalizedString
+ /**
+ * Documentation
+ */
+ documentation: () => LocalizedString
+ /**
+ * Terms of service
+ */
+ tos: () => LocalizedString
+ /**
+ * Privacy policy
+ */
+ privacyPolicy: () => LocalizedString
+ /**
+ * Sign into your account
+ */
+ signIntoYourAccount: () => LocalizedString
+ combobox: {
+ /**
+ * Search
+ */
+ search: () => LocalizedString
+ /**
+ * No records found
+ */
+ noRecordsFound: () => LocalizedString
+ /**
+ * Create a record by typing the name in the search bar and pressing enter
+ */
+ createRecordHelpText: () => LocalizedString
+ /**
+ * Press enter or click here to create {0}
+ */
+ createRecordButtonText: (arg0: unknown) => LocalizedString
+ }
+ signInPage: {
+ /**
+ * Sign in
+ */
+ title: () => LocalizedString
+ /**
+ * This is not my computer
+ */
+ notMyComputer: () => LocalizedString
+ /**
+ * Reset password
+ */
+ resetPassword: () => LocalizedString
+ /**
+ * Your password is updated
+ */
+ yourPasswordIsUpdated: () => LocalizedString
+ /**
+ * Sign In
+ */
+ signIn: () => LocalizedString
+ /**
+ * Your new password is applied
+ */
+ yourNewPasswordIsApplied: () => LocalizedString
+ /**
+ * Sign in below
+ */
+ signInBelow: () => LocalizedString
+ /**
+ * Your account is disabled
+ */
+ yourAccountIsDisabled: () => LocalizedString
+ /**
+ * Contact your administrator if this feels wrong
+ */
+ contactYourAdminIfDisabled: () => LocalizedString
+ /**
+ * You've reached the hidden inactivity limit
+ */
+ youHaveReachedInactivityLimit: () => LocalizedString
+ /**
+ * Feel free to sign in again
+ */
+ feelFreeToSignInAgain: () => LocalizedString
+ }
+ signUpPage: {
+ /**
+ * Sign up
+ */
+ title: () => LocalizedString
+ /**
+ * Create your new account
+ */
+ createYourNewAccount: () => LocalizedString
+ }
+ resetPasswordPage: {
+ /**
+ * Reset password
+ */
+ title: () => LocalizedString
+ /**
+ * Set new password
+ */
+ fulfillTitle: () => LocalizedString
+ /**
+ * Set a new password
+ */
+ setANewPassword: () => LocalizedString
+ /**
+ * Expired
+ */
+ expired: () => LocalizedString
+ /**
+ * Your request has expired
+ */
+ requestHasExpired: () => LocalizedString
+ /**
+ * Request a new reset
+ */
+ requestANewReset: () => LocalizedString
+ /**
+ * Your request is invalid
+ */
+ invalidRequestTitle: () => LocalizedString
+ /**
+ * This could be due to it being expired, nonexsistent or something else
+ */
+ invalidRequestMessage: () => LocalizedString
+ /**
+ * New password
+ */
+ newPassword: () => LocalizedString
+ /**
+ * If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account.
+ */
+ requestSentMessage: () => LocalizedString
+ /**
+ * Request a password reset
+ */
+ requestAPasswordReset: () => LocalizedString
+ /**
+ * Your request was not found
+ */
+ requestNotFound: () => LocalizedString
+ /**
+ * Submit a new reset request below
+ */
+ submitANewRequestBelow: () => LocalizedString
+ }
+ app: {
+ /**
+ * Members
+ */
+ members: () => LocalizedString
+ }
+}
+
+export type Formatters = {}
diff --git a/code/app/src/i18n/i18n-util.async.ts b/code/app/src/i18n/i18n-util.async.ts
new file mode 100644
index 0000000..2e6717e
--- /dev/null
+++ b/code/app/src/i18n/i18n-util.async.ts
@@ -0,0 +1,42 @@
+// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten.
+/* eslint-disable */
+
+import { initFormatters } from './formatters'
+import type { Locales, Namespaces, Translations } from './i18n-types'
+import { loadedFormatters, loadedLocales, locales } from './i18n-util'
+
+const localeTranslationLoaders = {
+ en: () => import('./en'),
+ nb: () => import('./nb'),
+}
+
+const localeNamespaceLoaders = {
+ en: {
+ app: () => import('./en/app')
+ },
+ nb: {
+ app: () => import('./nb/app')
+ }
+}
+
+const updateDictionary = (locale: Locales, dictionary: Partial<Translations>): Translations =>
+ loadedLocales[locale] = { ...loadedLocales[locale], ...dictionary }
+
+export const importLocaleAsync = async (locale: Locales): Promise<Translations> =>
+ (await localeTranslationLoaders[locale]()).default as unknown as Translations
+
+export const loadLocaleAsync = async (locale: Locales): Promise<void> => {
+ updateDictionary(locale, await importLocaleAsync(locale))
+ loadFormatters(locale)
+}
+
+export const loadAllLocalesAsync = (): Promise<void[]> => Promise.all(locales.map(loadLocaleAsync))
+
+export const loadFormatters = (locale: Locales): void =>
+ void (loadedFormatters[locale] = initFormatters(locale))
+
+export const importNamespaceAsync = async<Namespace extends Namespaces>(locale: Locales, namespace: Namespace) =>
+ (await localeNamespaceLoaders[locale][namespace]()).default as unknown as Translations[Namespace]
+
+export const loadNamespaceAsync = async <Namespace extends Namespaces>(locale: Locales, namespace: Namespace): Promise<void> =>
+ void updateDictionary(locale, { [namespace]: await importNamespaceAsync(locale, namespace )})
diff --git a/code/app/src/i18n/i18n-util.sync.ts b/code/app/src/i18n/i18n-util.sync.ts
new file mode 100644
index 0000000..8144fdc
--- /dev/null
+++ b/code/app/src/i18n/i18n-util.sync.ts
@@ -0,0 +1,35 @@
+// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten.
+/* eslint-disable */
+
+import { initFormatters } from './formatters'
+import type { Locales, Translations } from './i18n-types'
+import { loadedFormatters, loadedLocales, locales } from './i18n-util'
+
+import en from './en'
+import nb from './nb'
+
+import en_app from './en/app'
+import nb_app from './nb/app'
+
+const localeTranslations = {
+ en: {
+ ...en,
+ app: en_app
+ },
+ nb: {
+ ...nb,
+ app: nb_app
+ },
+}
+
+export const loadLocale = (locale: Locales): void => {
+ if (loadedLocales[locale]) return
+
+ loadedLocales[locale] = localeTranslations[locale] as unknown as Translations
+ loadFormatters(locale)
+}
+
+export const loadAllLocales = (): void => locales.forEach(loadLocale)
+
+export const loadFormatters = (locale: Locales): void =>
+ void (loadedFormatters[locale] = initFormatters(locale))
diff --git a/code/app/src/i18n/i18n-util.ts b/code/app/src/i18n/i18n-util.ts
new file mode 100644
index 0000000..5b7b6ed
--- /dev/null
+++ b/code/app/src/i18n/i18n-util.ts
@@ -0,0 +1,45 @@
+// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten.
+/* eslint-disable */
+
+import { i18n as initI18n, i18nObject as initI18nObject, i18nString as initI18nString } from 'typesafe-i18n'
+import type { LocaleDetector } from 'typesafe-i18n/detectors'
+import type { LocaleTranslationFunctions, TranslateByString } from 'typesafe-i18n'
+import { detectLocale as detectLocaleFn } from 'typesafe-i18n/detectors'
+import { initExtendDictionary } from 'typesafe-i18n/utils'
+import type { Formatters, Locales, Namespaces, Translations, TranslationFunctions } from './i18n-types'
+
+export const baseLocale: Locales = 'en'
+
+export const locales: Locales[] = [
+ 'en',
+ 'nb'
+]
+
+export const namespaces: Namespaces[] = [
+ 'app'
+]
+
+export const isLocale = (locale: string): locale is Locales => locales.includes(locale as Locales)
+
+
+ export const isNamespace = (namespace: string): namespace is Namespaces => namespaces.includes(namespace as Namespaces)
+
+export const loadedLocales: Record<Locales, Translations> = {} as Record<Locales, Translations>
+
+export const loadedFormatters: Record<Locales, Formatters> = {} as Record<Locales, Formatters>
+
+export const extendDictionary = initExtendDictionary<Translations>()
+
+export const i18nString = (locale: Locales): TranslateByString => initI18nString<Locales, Formatters>(locale, loadedFormatters[locale])
+
+export const i18nObject = (locale: Locales): TranslationFunctions =>
+ initI18nObject<Locales, Translations, TranslationFunctions, Formatters>(
+ locale,
+ loadedLocales[locale],
+ loadedFormatters[locale]
+ )
+
+export const i18n = (): LocaleTranslationFunctions<Locales, Translations, TranslationFunctions> =>
+ initI18n<Locales, Translations, TranslationFunctions, Formatters>(loadedLocales, loadedFormatters)
+
+export const detectLocale = (...detectors: LocaleDetector[]): Locales => detectLocaleFn<Locales>(baseLocale, locales, ...detectors)
diff --git a/code/app/src/i18n/nb/app/index.ts b/code/app/src/i18n/nb/app/index.ts
new file mode 100644
index 0000000..6bf9ba6
--- /dev/null
+++ b/code/app/src/i18n/nb/app/index.ts
@@ -0,0 +1,7 @@
+import type { NamespaceAppTranslation } from '../../i18n-types'
+
+const nb_app: NamespaceAppTranslation = {
+ members: "Medlemmer"
+}
+
+export default nb_app
diff --git a/code/app/src/i18n/nb/index.ts b/code/app/src/i18n/nb/index.ts
new file mode 100644
index 0000000..ef67504
--- /dev/null
+++ b/code/app/src/i18n/nb/index.ts
@@ -0,0 +1,51 @@
+import type { Translation } from "../i18n-types";
+
+const nb: Translation = {
+ or: "Eller",
+ name: "Navn",
+ emailAddress: "E-postadresse",
+ password: "Passord",
+ pageNotFound: "Fant ikke siden",
+ noInternet: "Det ser ut som at du ikke tilkoblet internettet, sjekk tilkoblingen din for å fortsette",
+ reset: "Tilbakestill",
+ of: "{0} av {1}",
+ isRequired: "{0} er påkrevd",
+ submit: "Send",
+ success: "Suksess",
+ tryAgainSoon: "Prøv igjen snart",
+ createANewAccount: "Lag en ny konto",
+ unexpectedError: "En uventet feil oppstod",
+ notFound: "Ikke funnet",
+ documentation: "Dokumentasjon",
+ tos: "Vilkår",
+ privacyPolicy: "Personvernerklæring",
+ signIntoYourAccount: "Logg inn med din konto",
+ signInPage: {
+ notMyComputer: "Dette er ikke min datamaskin",
+ resetPassword: "Tilbakestill passord",
+ yourPasswordIsUpdated: "Ditt passord er oppdater",
+ signIn: "Logg inn",
+ yourNewPasswordIsApplied: "Ditt nye passord er satt",
+ signInBelow: "Logg inn nedenfor",
+ yourAccountIsDisabled: "Din konto er deaktivert",
+ contactYourAdminIfDisabled: "Ta kontakt med din administrator hvis dette føles feil",
+ youHaveReachedInactivityLimit: "Du har nådd den hemmelige inaktivitetsgrensen",
+ feelFreeToSignInAgain: "Logg gjerne inn igjen"
+ },
+ signUpPage: {
+ createYourNewAccount: "Opprett din nye konto",
+ },
+ resetPasswordPage: {
+ setANewPassword: "Skriv et nytt passord",
+ expired: "Utgått",
+ requestHasExpired: "Din forespørsel er utgått",
+ requestANewReset: "Spør om en ny tilbakestillingslenke",
+ newPassword: "Nytt passord",
+ requestSentMessage: "Hvis vi finner e-postadressen din i våre systemer, vil du få en e-post med instrukser for å sette ditt nye passord.",
+ requestAPasswordReset: "Forespør tilbakestilling av ditt passord",
+ requestNotFound: "Din forespørsel ble ikke funnet",
+ submitANewRequestBelow: "Spør om en ny tilbakestillingslenke nedenfor"
+ }
+}
+
+export default nb; \ No newline at end of file