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

@iyio/ni18

v0.0.19

Published

Add internationalization support NextJS SSG ( next export )

Downloads

8

Readme

@iyio/ni18

ni18 adds internationalization support to NextJS projects using SSG ( next export ) without the need to modify routing.

Features

  • Generates static builds for each specified locale
  • Create SEO crawlable internationalized static sites
  • Support for both url based and cookie based language selection for both seamless language switching for end users and SEO
  • Builtin support for Firebase hosting i18n re-writes
    • https://firebase.google.com/docs/hosting/i18n-rewrites
  • Generation of locale-specific URLs using subdirectories with gTLD, fully compatible with Google SEO
    • https://developers.google.com/search/docs/advanced/crawling/managing-multi-regional-sites#locale-specific-urls

Installation


npm i @iyio/ni18

# -or-

pnpm i @iyio/ni18

# -or-

yarn add @iyio/ni18

Configuration

1. Create a config file named ni18-config.json

./ni18-config.json

{
    "defaultLocale":"en-US",
    "locales":["en-US","es-MX"],
    "domain":"example.com"
}

(note. Domain is needed to support alternate language page links and is not required during development)

2. Add ReactNi18Context.Provider to the App component

./pages/_app.(jsx|tsx)

import type { AppProps } from 'next/app'
import '../styles/globals.css'
+import Head from 'next/head';
+import { initNi18, useNi18Links } from '@iyio/ni18';
+import i18nConfig from '../ni18-config.json';

+initNi18(ni18Config)
 
function MyApp({ Component, pageProps }: AppProps) {

+  const localeLinks=useNi18Links(locales);

  return (
+    <>
+      <Head>
+        {localeLinks}
+      </Head>
      <Component {...pageProps} />
+    </>
  )
 }
 
 export default MyApp

3. Apply ni18 config to next.config.js using the withNi18 function

./next.config.js

+const { withNi18 } = require('@iyio/ni18')

/** @type {import('next').NextConfig} */
-const nextConfig = {
+const nextConfig = withNi18({
  reactStrictMode: true,
-}
+})

module.exports = nextConfig;

4. Add git ignore for build output and dev overrides

./.gitignore

+ # i18n
+ /out-ni18
+ .ni18-dev-override

6. ( optional ) Update build command

./package.json

{
  "name": "next-default",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
-    "build": "next build",
+    "build": "ni18",
    "start": "next start",
    "lint": "next lint"
  },

  ...

7. ( optional ) Add dev-ni18 api route to support switch languages in development mode

./pages/api/dev-ni18.(js|ts)

import { devNi18Handler as handler } from "@iyio/ni18";
export default handler;

Usage in code

The primary functions used while coding are the locale and setLocaleAsync functions, they get and set the current locale.

/**
 * Returns the current language and region (i.e. en-US)
 * locale() is shorthand for getNi18Locale().tag
 */
function locale():string;

/**
 * Sets the current locale. Calling this function server side will not effect clients
 */
async function setLocaleAsync(locale:string|Ni18Locale|null);

Usage example

import type {GetStaticProps, NextPage} from 'next'
import { locale, region, lang, setLocaleAsync } from '@iyio/ni18';

export const getStaticProps:GetStaticProps<LocaleExampleProps>=async ()=>
{
  // Use locale() in api request to get content                            👇
  const response=await fetch(`https://awesome.io/api/cool-stuff?locale=${locale()}`);
  const content=await response.json();
  return {props:{awesomeContent:content}}
}

interface LocaleExampleProps
{
  header:string;
  body:string;
}

const LocaleExample:NextPage<LocaleExampleProps>=({
  header,
  body
})=>{

  return (
    <div>

      {/* Show current locale 👇 ( en-US ) */}
      <h2>Current locale is {locale()}</h2>

      {/* Show current language 👇 ( en ) */}
      <h2>Current language is {lang()}</h2>

      {/* Show current region 👇 ( US ) */}
      <h2>Current region is {region()}</h2>

      <p>
        {/* Set the current locale            👇                 */}
        <button onClick={()=>setLocaleAsync('en-US')}>en-US</button>
        <button onClick={()=>setLocaleAsync('es-MX')}>es-MX</button>
      </p>

      <h2>Content from API</h2>
      <h3>{header}</h3>
      <p>{body}</p>
    </div>
  )
}

export default LocalExample;

Usage at build time

The ni18 command can be used via npx or directly from package scripts

# Build from command line

# use default config (./ni18-config.json)
npx ni18

# use with custom config and domain
npx ni18 -c custom-config.json --domain example.com

./package.json

{
    "scripts":{
        "build":"ni18"
    }
}

Config files

ni18 config files implement the Ni18Config interface.

(note. aliases are used by the cli. Config arguments can be passes by property name or alias )

export interface Ni18Config
{

    /**
     * The default locale. This value must be included in the locales property. If not defined in
     * the ni18 config file the first locale in the locales property will be used.
     * @alias z
     */
    defaultLocale:string;

    /**
     * An array of supported locales.
     * @example ['en','en-US','es','es-MX','da-DK']
     * @alias r
     */
    locales:string[];

    /**
     * Creates aliases for locales. This is useful for when you want to use a single locale build
     * for multiple locales. For example, if all of your content has a locale of either en (english)
     * or es (spanish) but you want locale builds for en, en-US, es and es-MX you can create aliases
     * that point en-US to en and es-MX to es ( {"en-US":"en", "es-MX":"es"} ). Using aliases
     * instead of defining locales in the locales property reduces the number of locale builds since
     * only the source locale is built and the alias is created by coping the build output of the
     * source locale.
     *
     * CLI format: alias=source, es-US=en
     * @alias m
     */
    localeMappings?:{[locale:string]:string};

    /**
     * The domain the build targets. This is required for alternate language links to work
     * properly
     * @alias d
     */
    domain:string;

    /**
     * The directory ni18 builds are written to.
     * @default './out-ni18
     * @alias o
     */
    out:string;

    /**
     * The directory that NextJS exports to
     * @default ./out
     * @alias n
     */
    nextOut:string;

    /**
     * If true build output will be moved to the nextOut location. This is helpful for integrating
     * in to existing build systems.
     * @default true
     * @alias w
     */
    swapOut:boolean;

    /**
     * The name of sub-directory where language specify builds are written to. The files written
     * here are browse-able and are used by search engines to index.
     * @alias l
     */
    localesSubDir:string;

    /**
     * The name of sub-directory where cookie based language specify builds are written to.
     * The files written here are not intended to be directly browse-able. They are used by
     * i18n url rewrites to support cookie based language switching.
     * @alias k
     */
    cookiesLocalesSubDir:string;
}

Example ni18 config file

{
    "defaultLocale":"en-US",
    "locales":["en-US","es-MX"],
    "domain":"example.com",
    "out":"./out-ni18",
    "nextOut":"./out",
    "localesSubDir":"lr",
    "cookiesLocalesSubDir":"lrc",
}

Command line args

ni18 command line args implement the Ni18CliArgs interface which extends the Ni18Config interface. Arguments can be passed either by property name preceded by 2 hyphens ( ---{propName} ) or by alias preceded by a single hyphen ( -{alias})

export interface Ni18CliArgs extends Partial<Ni18Config>
{
    /**
     * Path of a ni18 config files
     * @alias c
     */
    config?:string;

    /**
     * Source directory of the target next project
     * @alias s
     */
    src?:string;
}

The below examples are equivalent, the first example uses property names and the other uses aliases


# using property names
ni18 --domain example.com --localesSubDir other-languages --locales en-US es-MX

# using aliases
ni18 -d example.com -l other-languages -r en-US es-MX