Can anyone assist me with creating a reusable component for `next-intl` that can be

Let me explain what I'm looking for. If you're not familiar with next-intl, it's a package designed to provide internationalization support for Next.js applications.

The Issue:

The developer of next-intl is working on a beta version that supports the app router in next.js. I have installed this beta version successfully.

The problem arises when using next-intl in async components, as developers are required to move the calling of the useTranslations hook to a synchronous component instead.

Since I use async components extensively, I created a reusable component called <T /> (which stands for Text or Translation) to pass the translation key as a prop. For example:

<T k="home.hero.title" />
.

My Approach:

Assuming the translation file follows this structure:

{
  "hello-world": "Hello World",
  "home": {
    "title": "Acme",
    "hero": {
      "description": "whatever"
    }
  },
  "login": {
    "button": "Login"
  }
}

components/translation.tsx

import { useTranslations } from "next-intl";

export function T({ k }: {
  k: TYPEME_LATER;
}) {
  const translate = useTranslations();
  return translate(k);
}

The crux of my question revolves around the TYPEME_LATER issue.

1. Initial Attempt:

import { useTranslations } from "next-intl";

type TranslationKey = Parameters<ReturnType<typeof useTranslations>>[0];

export function T({ k }: {
  k: TranslationKey;
}) {}

However, this approach only suggests nested keys like title, hero.description, button, and hello-world. Although TypeScript recognizes these keys, next-intl fails to locate them within the scope of home and login.

2. Alternative Solution:

import { useTranslations } from "next-intl";

type useTranslationsParam = Parameters<typeof useTranslations>[0];
type TranslationKey = Parameters<ReturnType<typeof useTranslations>>[0];

export function T({
  scope,
  k,
}: {
  scope: useTranslationsParam;
  k: TranslationKey;
}) {
  const translate = useTranslations(scope);
  return translate(k);
}

Surprisingly, this solution worked perfectly. Now, I can easily implement it anywhere in the codebase:

export default async function Page() {
  return <>
    <T scope="home" k="title" />
  </>
}

While this renders correctly, there is a concern regarding the TranslationKey type declaration, which currently accepts any key regardless of the specified scope. This could potentially lead to bugs if an incorrect key is used outside the designated scope.

My query is how to limit the suggestions for the k prop to keys within the specified scope. Any alternative approaches would be greatly appreciated.

Thank you for your attention and assistance.

Answer №1

New Information

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6709021f134a0e09130b27544956">[email protected]</a>
introduced async component support with
await getTranslations(namespace?)

export async function Page() {
  const t = await getTranslations("home");
  
  return <div>{t("title")}</div>
}


Solution Overview

This is the final implementation for those interested in building a similar feature:

import { useTranslations } from "next-intl";

interface Props {
  /** Message key */
  path: Paths<IntlMessages>;
}

export function Text({ path: key }: Props) {
  const translate = useTranslations();

  return translate(key);
}

type Paths<Schema, Path extends string = ""> = Schema extends string
  ? Path
  : Schema extends object
  ? {
      [K in keyof Schema & string]: Paths<
        Schema[K],
        `${Path}${Path extends "" ? "" : "."}${K}`
      >;
    }[keyof Schema & string]
  : never;

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

The type 'angular' does not have a property of this kind

Having trouble importing a method into my Angular component. An error keeps popping up: Property 'alerta' does not exist on type 'typeof PasswordResetService'. any I've double-checked the code and everything seems to be in order! ...

I encountered a typescript error while trying to export my Class component within a Higher Order Component (HOC)

I'm encountering a TypeScript error with my HomePage Class Component. Below is the code snippet: import * as React from "react"; import { Dispatch, AnyAction } from 'redux'; import { connect } from 'react-redux&apos ...

Establishing MQTT Connection in Ionic 3

I am facing a challenge with implementing Publish-Subscribe methods in my Ionic 3 application. After consulting the information on this page, I attempted to link MQTT with my Ionic 3 application. Can anyone guide me on how to successfully connect MQTT wi ...

deduce the parameter types of a function using the keys of an object

In the following code snippet, my goal is to have the argument type of fn inferred based on the values provided in args. I aim for good to be automatically inferred as boolean, num as a number and bad to trigger an error. Currently, all of them are consi ...

Identifying misspelled names in shared resources textures during PIXI.js loading

Our game utilizes TypeScript, Pixi.js, VSCode, and ESLint. We maintain a dictionary of image files as follows: export function getAllImages(): {name: string, extension: string}[] { return [ {name: 'tile_lumber', extension: '.svg ...

What is the best way to completely eliminate a many-to-many relationship with a custom property?

I have encountered a situation where I am utilizing an entity setup similar to the one explained in this resource. The problem arises when I try to remove entries from post.postToCategories. Instead of deleting the entire row, TypeORM sets one side of the ...

What role does typescript play in this approach?

test.js const testList = [1, 2, 2, 4, 5, 2, 4, 2, 4, 5, 5, 6, 7, 7, 8, 8, 8, 1, 4, 1, 1]; const lastIndex = testList.findLastIndex((e:number) => e === 100); // Property 'findLastIndex' does not exist on type 'number[]'. Did you mean ...

Extract the date and time information from the API response

I have received a response array from an API that I need to work with. Take a look at the response below: [{createdBy:"user1", updatedDttm: "2022-01-20T07:31:35.544Z"}, {createdBy:"user2", updatedDttm: "2022-02-20T09:31:3 ...

Retrieve class attributes within callback function

I have integrated the plugin from https://github.com/blinkmobile/cordova-plugin-sketch into my Ionic 3 project. One remaining crucial task is to extract the result from the callback functions so that I can continue working with it. Below is a snippet of ...

Utilize Angular 4 to effectively update objects within Firebase Cloud Firestore

Hey there! I've been working with firebase and angular 4 on this new thing called firestore. I've been trying to update one of the documents, but I keep encountering this error. https://i.sstatic.net/638E1.png Here's my component: https:/ ...

Storing user input as an object key in typescript: A comprehensive guide

When delving into Firestore for the first time, I quickly learned that the recommended modeling approach looks something like this: check out the model here members { id: xyz { name: Jones; ...

What is the best way to list the choices associated with a specific category?

The Node.js package I'm currently working with requires an argument of a specific type, which I can see is defined through a TypeScript declaration as follows: export declare type ArgType = 'A' | 'B' | 'C'; I am interes ...

Upon clicking a button, I aim to retrieve the data from the rows that the user has checked. I am currently unsure of how to iterate through the rows in my mat-table

My goal is to iterate through the column of my mat-table to identify the rows that have been checked, and then store the data of those rows in an array. <td mat-cell *matCellDef="let row"> <mat-checkbox (click)="$event.stopPropagation()" (c ...

Importing configuration file in CRA Typescript with values for post-deployment modifications

I am currently working on a React app that utilizes Create React App and Typescript. My goal is to read in configuration values, such as API URLs. I have a config.json file containing this data, here's a sample snippet with placeholder information: { ...

Guide on incorporating Paddle into your SvelteKit project

I'm struggling to implement a Paddle Inline Checkout in SvelteKit. Every time I try, I keep encountering the error message Name Paddle not found. It seems like the script is not functioning properly. Console Error: Uncaught (in promise) ReferenceErro ...

Creating a Variety of Files in the Angular Compilation Process

Currently, I am developing an Angular project and faced with the task of creating various files during the build process depending on certain conditions or setups. I would appreciate any advice on how to accomplish this within the Angular framework. I att ...

Is it possible to generate an array of strings from the keys of a type or interface?

Imagine a scenario where we have a type or interface defined as NumberLookupCriteria: type NumberLookupCriteria = { dialCode: string; phoneNumber: string; } or interface NumberLookupCriteria { dialCode: string; phoneNumber: string; } Is there a w ...

Problem with RxJS array observable functionality not meeting expectations

I am struggling with an Angular service that contains an array of custom objects and an observable of this array. An external component subscribes to the observable but does not respond when the list is modified. Additionally, the mat-table, which uses the ...

What is the proper way to define a new property for an object within an npm package?

Snippet: import * as request from 'superagent'; request .get('https://***.execute-api.eu-west-1.amazonaws.com/dev/') .proxy(this.options.proxy) Error in TypeScript: Property 'proxy' is not found on type 'Super ...

The program is requesting an expression involving the user's username

https://i.stack.imgur.com/tf1QD.png What is causing the issue with trying to use user.username? as an expression? While user.username returns a string of the User's username, I am unable to index it into listOfPlayers[]. client.on("messageReacti ...