npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sdjzwiki/next-locale

v1.0.1

Published

A simple and powerful i18n translation system for Next.js 14+.

Downloads

127

Readme

NextLocale

简体中文

NextLocale is a multilingual (internationalization) solution built specifically for Next.js 14+ projects. It's simple, lightweight, and allows you to easily switch project languages while automatically handling the loading and caching of language files.

Why I Created NextLocale

I was using Next.js version 14, and it completely clashed with popular translation libraries like i18next and react-intl, causing constant errors. It got so frustrating that I was about to have a cyber meltdown. These libraries are also often overcomplicated, requiring a lot of extra configuration.

So, I decided to create a lightweight but powerful solution, specifically designed for Next.js 14+, to solve these compatibility issues and reduce unnecessary complexity.

The main goal of NextLocale is that with just a few steps of configuration, you can bring global multilingual support to your Next.js project. It comes with smooth animation transitions, caching support, and allows easy dynamic language switching. No more manually tweaking your page logic for different languages.

Installation

First, install the library in your project:

pnpm add @sdjzwiki/next-locale

Or if you're using npm or yarn:

npm install @sdjzwiki/next-locale
yarn add @sdjzwiki/next-locale

Step 1: Configure Language Files

We first need to create a file to define the languages supported by the system. This file is called languages.ts.

Its purpose is to manage the available language options (like display names and language codes) and will be used in the language-switching logic.

1. Create src/lib/languages.ts

In your project, create a new file called src/lib/languages.ts and add the following content:

// Define the format for supported languages
export interface Language {
    code: string;        // The language code, like 'en' for English
    name: string;        // The language name, like 'English'
    translationKey: string; // The name of the translation file, like 'translation_en'
    beta?: boolean;      // Optional property to mark a language as beta
}

// Define the list of supported languages
export const defaultLanguages: Language[] = [
    { code: 'en', name: 'English', translationKey: 'translation_en' },
    { code: 'zh_cn', name: '简体中文', translationKey: 'translation_zh_cn', beta: true },
    { code: 'es', name: 'Español', translationKey: 'translation_es' },
];

Explanation:

  • code: The shorthand for the language, like 'en' for English, 'zh_cn' for Simplified Chinese.
  • name: The display name of the language, which will be shown in the user interface, like "简体中文" or "Español."
  • translationKey: Used to find the corresponding translation file, which you'll use later.
  • beta: An optional field to mark a language as a beta version. For example, you might be developing the translation for a new language.

Step 2: Create Middleware

This middleware will detect the user's browser language or existing language cookie and automatically switch languages based on this information.

1. Create middleware.ts

In the root directory of your project, create a new file called middleware.ts with the following content:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

// Define the list of supported languages
const supportedLanguages = new Set([
    'en', 'zh_cn', 'es'
]);

export function middleware(req: NextRequest) {
    const url = req.nextUrl.clone();
    const acceptLanguage = req.headers.get('Accept-Language');

    let lang = 'en';  // Default language
    const cookieLang = req.cookies.get('NEXT_LOCALE');

    if (cookieLang) {
        lang = cookieLang.value.toLowerCase();
    } else if (acceptLanguage) {
        const languages = acceptLanguage.split(',').map(l => l.split(';')[0].trim().toLowerCase());
        for (const l of languages) {
            const formattedLang = l.replace('-', '_');
            if (supportedLanguages.has(formattedLang)) {
                lang = formattedLang;
                break;
            }
        }
    }

    if (!cookieLang && lang) {
        const response = NextResponse.redirect(url);
        response.cookies.set('NEXT_LOCALE', lang, { path: '/' });
        return response;
    }

    return NextResponse.next();
}

export const config = {
    matcher: ['/((?!api|_next|favicon.ico).*)'],
};

Explanation:

  • This middleware checks the user's language on every request and sets a NEXT_LOCALE cookie that stores their language preference.
  • Accept-Language is a request header sent by the browser that contains the user's preferred language. We extract the preferred language from this header.
  • If the user has previously selected a language, the system will remember and use their chosen language.
  • If no language has been selected before, we automatically choose one based on the browser's language settings and set a cookie.
  • If the user manually switches languages on the frontend, the cookie will be updated to reflect the new language.

Step 3: Wrap the LanguageProvider

Next, you need to wrap the root of your app with a LanguageProvider to provide multilingual support throughout your app.

1. Modify _app.tsx

Open your _app.tsx file and wrap the LanguageProvider:

import { LanguageProvider } from '@sdjzwiki/next-locale';

function MyApp({ Component, pageProps }) {
    return (
        <LanguageProvider>
            <Component {...pageProps} />
        </LanguageProvider>
    );
}

export default MyApp;

If you're using layout.tsx, it works similarly:

import { LanguageProvider } from '@sdjzwiki/next-locale';

export default function RootLayout({
                                       children,
                                   }: Readonly<{
    children: React.ReactNode;
}>) {

    return (
                <LanguageProvider>
                    {children}
                </LanguageProvider>
    );
}

Step 4: Use the useTranslation Hook

NextLocale provides a useTranslation Hook to get the current language and perform translation operations.

Here are two demos to help you understand how to use it:

1. Translating Text

Suppose you have a component that needs to display different text based on the current language:

import { useTranslation } from '@sdjzwiki/next-locale';

const Component = () => {
    const { t } = useTranslation();

    return (
        <div>
            <p>{t('welcome_message')}</p>
        </div>
    );
};

export default Component;

2. Getting and Switching Languages

import { useTranslation } from '@sdjzwiki/next-locale';
import { defaultLanguages } from '@/lib/languages';

const LanguageSwitcher = () => {
    const { language, setLanguage } = useTranslation();  // Get translation function and language switcher

    return (
        <div>
            {/* Language switch buttons */}
            {defaultLanguages.map((lang) => (
                <button key={lang.code} onClick={() => setLanguage(lang.code)}>
                    {lang.name}
                </button>
            ))}
        </div>
    );
};

export default LanguageSwitcher;

Explanation:

  • The useTranslation Hook returns an object that contains the t function, the language property, and the setLanguage function.
  • The t function is used to translate text; it takes a key as an argument and returns the corresponding translation.
  • The language property represents the current language.
  • The setLanguage function is used to switch languages, accepting a language code as an argument and updating the current language. It automatically updates the NEXT_LOCALE cookie, ensuring the correct language is used on the next visit.

Step 5: Add Translation Files

In the last step, you'll need to create a translation file for each language under the public folder. For example:

1. Create Translation Files

In your project, create the following directory and files:

public/
  └── locales/
      ├── en/
      │   └── common.json
      ├── zh_cn/
      │   └── common.json
      └── es/
          └── common.json

Each common.json file contains the text you want to translate. For example, the public/locales/en/common.json file would look like this:

{
    "welcome_message": "Welcome to our website!"
}

And public/locales/zh_cn/common.json could look like this:

{
    "welcome_message": "欢迎来到我们的网站!"
}

The common.json file is used to store translation content for each language. The t('welcome_message') function will look up this key in the file. Each language has its own folder under public/locales.

License

This project is licensed under the MIT License, meaning you can use and modify it freely, but don't forget to give credit.

If you think it's cool, give it a star ✨!