diff --git a/@navikt/core/react/src/form/form-progress/FormProgress.stories.tsx b/@navikt/core/react/src/form/form-progress/FormProgress.stories.tsx index 5135ee4517..b9dce0ea95 100644 --- a/@navikt/core/react/src/form/form-progress/FormProgress.stories.tsx +++ b/@navikt/core/react/src/form/form-progress/FormProgress.stories.tsx @@ -1,6 +1,7 @@ import { Meta, StoryFn } from "@storybook/react"; import React, { useState } from "react"; import VStack from "../../layout/stack/VStack"; +import UNSAFE_AkselLanguageProvider from "../../provider/i18n/LanguageProvider"; import FormProgress, { FormProgressProps } from "./FormProgress"; export default { @@ -37,6 +38,97 @@ export const Default: StoryFn = (props) => ( ); Default.args = { activeStep: 2, totalSteps: 7, interactiveSteps: true }; +export const ProvidedTranslations: StoryFn = () => { + const translations = { + FormProgress: { + step: "Step {activeStep} of {totalSteps}", + showAllSteps: "Show all steps", + hideAllSteps: "Hide all steps", + }, + }; + + return ( + + + + Start søknad + + Personopplysninger + + Saksopplysninger + + + Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst + + Vedlegg + Oppsummering + Innsending + + + ); +}; + +export const DefaultTranslations: StoryFn = () => { + return ( + + + + Start søknad + + Personopplysninger + + Saksopplysninger + + + Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst + + Vedlegg + Oppsummering + Innsending + + + ); +}; + +export const ComponentTranslations: StoryFn = () => { + const globalTranslations = { + FormProgress: { + step: "Step {activeStep} of {totalSteps}", + showAllSteps: "Show all steps", + hideAllSteps: "Hide all steps", + }, + }; + const translations = { + step: "Skref {activeStep} af {totalSteps}", + showAllSteps: "Sýndu öll skref", + hideAllSteps: "Fela öll skref", + }; + return ( + + + + Start søknad + + Personopplysninger + + Saksopplysninger + + + Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst + + Vedlegg + Oppsummering + Innsending + + + ); +}; + export const Controlled: StoryFn = () => { const [open, setOpen] = useState(true); return ( diff --git a/@navikt/core/react/src/provider/i18n/LanguageProvider.tsx b/@navikt/core/react/src/provider/i18n/LanguageProvider.tsx new file mode 100644 index 0000000000..cd98e6a50d --- /dev/null +++ b/@navikt/core/react/src/provider/i18n/LanguageProvider.tsx @@ -0,0 +1,51 @@ +import React, { createContext, useContext } from "react"; +import { TranslationDictionary } from "../../util/i18n/i18n.types"; +import nb from "../../util/i18n/locales/nb"; + +export interface LanguageProviderContextType { + /** + * Merged with the default language translations object (officially provided translations). + */ + translations: TranslationDictionary | TranslationDictionary[]; +} + +export const LanguageProviderContext = + createContext({ + translations: nb, + }); + +export interface LanguageProviderProps { + children?: React.ReactNode; + translations?: TranslationDictionary | TranslationDictionary[]; +} + +export const useProvider = () => useContext(LanguageProviderContext); + +/** + * @private Feature is under development and should not be used in any applications. + * + * @example + * ```jsx + * + * {app} + * + * ``` + */ +export const UNSAFE_AkselLanguageProvider = ({ + children, + translations, + ...rest +}: LanguageProviderProps) => { + return ( + + {children} + + ); +}; + +export default UNSAFE_AkselLanguageProvider; diff --git a/@navikt/core/react/src/util/i18n/i18n.context.test.tsx b/@navikt/core/react/src/util/i18n/i18n.context.test.tsx index 5ab9ba8cfa..d7a05d5f34 100644 --- a/@navikt/core/react/src/util/i18n/i18n.context.test.tsx +++ b/@navikt/core/react/src/util/i18n/i18n.context.test.tsx @@ -1,7 +1,8 @@ import { renderHook } from "@testing-library/react"; import React from "react"; import { describe, expect, test } from "vitest"; -import { I18nContext, useI18n } from "./i18n.context"; +import UNSAFE_AkselLanguageProvider from "../../provider/i18n/LanguageProvider"; +import { useI18n } from "./i18n.context"; describe("useI18n", () => { test("should throw error if key is not found", () => { @@ -15,7 +16,9 @@ describe("useI18n", () => { const i18n = { FileUpload: { item: { uploading: "Test translation" } } }; const { result } = renderHook(() => useI18n("FileUpload"), { wrapper: ({ children }) => ( - {children} + + {children} + ), }); const translate = result.current; @@ -29,9 +32,9 @@ describe("useI18n", () => { const i18n2 = { FileUpload: { item: { uploading: "Wrong translation" } } }; const { result } = renderHook(() => useI18n("FileUpload"), { wrapper: ({ children }) => ( - + {children} - + ), }); const translate = result.current; @@ -45,9 +48,9 @@ describe("useI18n", () => { }; const { result } = renderHook(() => useI18n("FileUpload"), { wrapper: ({ children }) => ( - + {children} - + ), }); const translate = result.current; diff --git a/@navikt/core/react/src/util/i18n/i18n.context.ts b/@navikt/core/react/src/util/i18n/i18n.context.ts index 9a56eefabd..fe0d07f55e 100644 --- a/@navikt/core/react/src/util/i18n/i18n.context.ts +++ b/@navikt/core/react/src/util/i18n/i18n.context.ts @@ -1,10 +1,7 @@ -import { createContext, useContext } from "react"; +import { useContext } from "react"; +import { LanguageProviderContext } from "../../provider/i18n/LanguageProvider"; import { get } from "./get"; -import { - Component, - ComponentTranslation, - TranslationDictionary, -} from "./i18n.types"; +import { Component, ComponentTranslation } from "./i18n.types"; import nb from "./locales/nb"; /** @@ -12,10 +9,6 @@ import nb from "./locales/nb"; */ const REPLACE_REGEX = /{[^}]*}/g; -export const I18nContext = createContext< - TranslationDictionary | TranslationDictionary[] ->(nb); - /* https://dev.to/pffigueiredo/typescript-utility-keyof-nested-object-2pa3 */ type NestedKeyOf = { [Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object @@ -27,7 +20,8 @@ export function useI18n( componentName: T, ...local: (ComponentTranslation | undefined)[] ) { - const i18n = useContext(I18nContext); + const languageProviderContext = useContext(LanguageProviderContext); + const i18n = languageProviderContext.translations; /** * https://github.com/Shopify/polaris/blob/2115f9ba2f5bcbf2ad15745233501bff2db81ecf/polaris-react/src/utilities/i18n/I18n.ts#L24