Retrieve a formatted item from a JSON document

Within my Next.js project, I have implemented a method for loading translations and passing them into the component. Here is an example:

import "server-only";
import i18nConfig from "../../i18n-config";

const dictionaries = {
  en: () =>
    import("../../dictionaries/en.json").then((module) => module.default),
  hr: () =>
    import("../../dictionaries/hr.json").then((module) => module.default),
};

type TDictionary = (typeof dictionaries)["en"];

export const getDictionary = async (locale: string): Promise<TDictionary> =>
  dictionaries[
    i18nConfig.locales.includes(locale) ? locale : i18nConfig.defaultLocale
  ]();
export default async function Navbar( props: ILangParams ) {
  const dict = await getDictionary(props.params.lang); 

  return (
    <nav className={styles.navbar}>
      <Link href="/" className={styles.linkLogo}>
        <Image
          priority
          src={logo}
          alt={dict.navbar.links.home}
          className={styles.logo}
        />
    </nav>
  );
}

If I don't specify that getDictionary should return Promise<TDictionary>, it defaults to Promise<any>.

By using Promise<TDictionary>, the returned structure looks like this:

const dict: () => Promise<{
    navbar: {
        links: {
            logoAlt: string;
            escapeGames: string;
            becomeAPartner: string;
            bookDemo: string;
        };
    };
}>

This causes issues as I am unable to access the translated strings using dict.navbar.links.home.

How can I correctly type this in order to utilize the translation keys?

The structure remains consistent across all translations, requiring only one cast ((typeof dictionaries)["en"]).

Answer №1

My code snippet is functional and very similar to the one you provided.

export type Language = "fr" | "en" | "zh"

const languageDictionaries = {
    fr: () => import('./dictionaries/fr.json').then((module) => module.default),
    en: () => import('./dictionaries/en.json').then((module) => module.default),
    zh: () => import('./dictionaries/zh.json').then((module) => module.default),
}

type DictionaryType = ReturnType<(typeof languageDictionaries)["fr"]>; // must be the return type 

// The type of lang needs to be a union type
// otherwise, it will trigger the error message "Element implicitly has an 'any' type"
export default async function retrieveDictionary(lang: Language): Promise<DictionaryType> {
    return languageDictionaries[lang]();
}

Answer №2

Why not try a different approach:

// @ts-ignore
export const getDictionary = async (locale: Locale) => dictionaries[locale]();

If you implement the above code, your issue should be resolved.

And don't forget to destructure the translation objects when calling the getDictionary function:</p>
<pre><code>const {home, navbar,...} = await getDictionary(props.params.lang); 

This simple change can make your task easier.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to modifying text color in a disabled Material-UI TextField | Material-UI version 5

How can I change the font color of a disabled MUI TextField to black for better visibility? See below for the code snippet: <TextField fullWidth variant="standard" size="small" id="id" name=&quo ...

Angular2: Ways to update components with resolver dependencies?

In my project, I have three separate components, each with its own resolver that retrieves data from distinct APIs. These components all depend on a shared URL provided by a service. My goal is to ensure that when the URL changes, each component refreshes ...

The ultimate guide to testing API routes in Next.js using Jest

In my api directory, there is a function that searches an array of services and retrieves a single service based on the slug provided. Here is the code for the API function: import {services} from '../../../public/data/service.js' export defaul ...

When defining a stripe in TypeScript using process.env.STRIPE_SECRET_KEY, an error of "string | undefined" is encountered

Every time I attempt to create a new stripe object, I encounter the error message "Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string& ...

Using a Jasmine spy to monitor an exported function in NodeJS

I've encountered difficulties when trying to spy on an exported function in a NodeJS (v9.6.1) application using Jasmine. The app is developed in TypeScript, transpiled with tsc into a dist folder for execution as JavaScript. Application Within my p ...

Is there a way to showcase the data of each table row within the tr tag in an Angular 8 application?

I have been developing an application using Angular 8. The employee-list component is responsible for presenting data in a table format. Within the employee-list.component.ts file, I have defined: import { Component } from '@angular/core'; impo ...

The TypeScript namespace does not exist or cannot be located

Currently, I am working on coding in TypeScript. The specific code pertains to an Angular 2 application, but the main focus of my inquiry lies within TypeScript itself. Within my project, there are certain files that contain various models, such as the exa ...

Creating a comprehensive object within a single interface using Typescript

Here is an example of an Object in TypeScript: export class test{ recordname: string; comments: [{ comment: string }] } To define it using one interface instead of multiple interfaces, you can try something like this: export int ...

Leverage TypeScript to enforce the value of a property based on the keys of another property

The issue at hand is illustrated in the following example: type ExampleType = { properties: { [x: string]: number; }; defaultProperty: string; }; const invalidExample: ExampleType = { properties: { foo: 123, }, defaultProperty: "n ...

Exploring React State Management: Leveraging the Context API as a centralized store for

Currently, I am developing a React web application using TypeScript. To enhance the State Management, I decided to implement React Hooks and Context API by following a concise tutorial that I came across here. Despite diligently following the tutorial, my ...

Error message indicating that the function is not defined within a custom class method

I successfully transformed an array of type A into an object with instances of the Person class. However, I'm facing an issue where I can't invoke methods of the Person class using the transformed array. Despite all console.log checks showing tha ...

Can parameters with identical union types in a function signature be streamlined to contain only the exact same subtypes using generic types?

// defining a type Combinable with string or number as possible values type Combinable = string | number; // function to check if parameter is a string function isString(param: unknown): param is string { return typeof param === "string"; } /** * Func ...

Vue defineProps allows for the definition of complex types for properties

Within my code, I am exploring the use of complex prop types in certain instances. Below is an example of what I have in mind: enum Country { [...] } interface IPerson { firstname: string; lastname: string; } interface IAddress { street: string; ...

Different ESLint configurations for mjs, js, and ts files

For my project, I've set up ESM (.mjs) files for server-side code, CommonJS (.js) for tooling, and TypeScript (.ts) for the client side. In VS Code, when I look at CommonJS files, I'm getting errors related to requires such as "Require statement ...

Is it feasible to send props to { children } within a React functional component?

Workaround presented below. I am attempting to send props down to a child component using {children}. The Parent component: const ParentComp = ({ children, propsToSendToChild }) => ( <div>Dynamic component content: {children} &l ...

Vue alert: Component resolution failed while attempting to create a global component

I am new to Vue Typescript and I have been encountering an issue while trying to create global components. I received a warning and the component did not load on the template. Here is how I attempted to create global components: App.vue import { createApp ...

Issue with Loading Images, Js, and Css After Build: All Files Returning 404 Error

As I endeavor to launch my latest 13 app, everything seems fine during the build process with no errors. However, when attempting to access the app, only HTML content appears, and a 404 error is displayed for Js, Css, and images (as evident in the network ...

The error message displayed by Create React App states: "You cannot utilize JSX without the '--jsx' flag."

I need help with overcoming this particular issue in a TypeScript based React application: Encountering an error stating "Cannot use JSX unless the '--jsx' flag is provided" ...

Angular 6 allows for the use of radio buttons to dynamically enable or disable corresponding fields

Here is the HTML code for a row containing radio button selections: <div class="form-row"> <div class="col-md-3 mb-3"> <div class = "form-group form-inline col-md-12 mb-3"> <div class="form-check form-check-inl ...

Utilizing Express JS to Optimize JPEG File Loading with Cache Headers

I have been working on implementing Cache-Control for my static image files. I have successfully set this header for HTML and JS files: https://i.stack.imgur.com/9VuWl.png However, I am facing challenges with JPEG files: https://i.stack.imgur.com/p52jm. ...