🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

next-intl

Package Overview
Dependencies
Maintainers
1
Versions
377
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

next-intl - npm Package Compare versions

Comparing version

to
0.0.3

LICENSE

10

dist/next-intl.cjs.development.js

@@ -16,6 +16,8 @@ 'use strict';

var children = _ref.children,
locale = _ref.locale,
messages = _ref.messages;
return React__default.createElement(NextIntlContext.Provider, {
value: {
messages: messages
messages: messages,
locale: locale
}

@@ -52,6 +54,3 @@ }, children);

var context = React.useContext(NextIntlContext);
var _useRouter = router.useRouter(),
locale = _useRouter.locale;
var nextLocale = router.useRouter().locale;
var cachedFormatsByLocaleRef = React.useRef({});

@@ -65,2 +64,3 @@

var locale = context.locale || nextLocale;
var allMessages = context.messages;

@@ -67,0 +67,0 @@ var messages = React.useMemo(function () {

@@ -1,2 +0,2 @@

"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var r=require("react"),t=e(r),n=e(require("intl-messageformat")),o=require("next/router"),u=r.createContext(void 0);function s(e,r){var t=e;return r.split(".").forEach((function(e){t=t[e]})),t}exports.NextIntlProvider=function(e){return t.createElement(u.Provider,{value:{messages:e.messages}},e.children)},exports.useTranslations=function(e){var t=r.useContext(u),i=o.useRouter().locale,a=r.useRef({});if(!t)throw new Error;var f=t.messages,c=r.useMemo((function(){return e?s(f,e):f}),[f,e]);return function(e,r){var t;if(!i)throw new Error;var o,u=a.current;if(null==(t=u[i])?void 0:t[e])o=u[i][e];else{var f=s(c,e);if("object"==typeof f)throw new Error;o=new n(f,i),u[i]||(u[i]={}),u[i][e]=o}return o.format(r)}};
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var r=require("react"),t=e(r),o=e(require("intl-messageformat")),n=require("next/router"),u=r.createContext(void 0);function a(e,r){var t=e;return r.split(".").forEach((function(e){t=t[e]})),t}exports.NextIntlProvider=function(e){return t.createElement(u.Provider,{value:{messages:e.messages,locale:e.locale}},e.children)},exports.useTranslations=function(e){var t=r.useContext(u),s=n.useRouter().locale,i=r.useRef({});if(!t)throw new Error;var l=t.locale||s,c=t.messages,f=r.useMemo((function(){return e?a(c,e):c}),[c,e]);return function(e,r){var t;if(!l)throw new Error;var n,u=i.current;if(null==(t=u[l])?void 0:t[e])n=u[l][e];else{var s=a(f,e);if("object"==typeof s)throw new Error;n=new o(s,l),u[l]||(u[l]={}),u[l][e]=n}return n.format(r)}};
//# sourceMappingURL=next-intl.cjs.production.min.js.map

@@ -9,6 +9,8 @@ import React, { createContext, useContext, useRef, useMemo } from 'react';

var children = _ref.children,
locale = _ref.locale,
messages = _ref.messages;
return React.createElement(NextIntlContext.Provider, {
value: {
messages: messages
messages: messages,
locale: locale
}

@@ -45,6 +47,3 @@ }, children);

var context = useContext(NextIntlContext);
var _useRouter = useRouter(),
locale = _useRouter.locale;
var nextLocale = useRouter().locale;
var cachedFormatsByLocaleRef = useRef({});

@@ -60,2 +59,3 @@

var locale = context.locale || nextLocale;
var allMessages = context.messages;

@@ -62,0 +62,0 @@ var messages = useMemo(function () {

@@ -5,3 +5,4 @@ /// <reference types="react" />

messages: Messages;
locale?: string | undefined;
} | undefined>;
export default NextIntlContext;

@@ -6,4 +6,5 @@ import { ReactNode } from 'react';

messages: NextIntlMessages;
locale?: string;
};
export default function NextIntlProvider({ children, messages }: Props): JSX.Element;
export default function NextIntlProvider({ children, locale, messages }: Props): JSX.Element;
export {};
{
"name": "next-intl",
"version": "0.0.2",
"version": "0.0.3",
"author": "Jan Amann <jan@amann.me>",
"description": "Minimal, but complete solution for managing translations in Next.js apps.",
"license": "MIT",
"description": "TODO",
"author": "Jan Amann <jan@amann.me>",
"repository": {
"type": "git",
"url": "https://github.com/amannn/react-hooks/tree/master/packages/next-intl"
"url": "https://github.com/amannn/next-intl"
},
"scripts": {
"start": "tsdx watch --tsconfig tsconfig.json --verbose --noClean",
"build": "tsdx build --tsconfig tsconfig.json",
"start": "tsdx watch",
"build": "tsdx build",
"test": "tsdx test",
"lint": "eslint src test && tsc --noEmit",
"prepublish": "npm run build"
"lint": "eslint src test && tsc",
"prepare": "tsdx build"
},

@@ -22,5 +22,8 @@ "main": "dist/index.js",

"files": [
"README.md",
"dist"
"dist",
"src"
],
"dependencies": {
"intl-messageformat": "^9.3.18"
},
"peerDependencies": {

@@ -31,12 +34,17 @@ "next": "^10.0.0",

},
"dependencies": {
"intl-messageformat": "^9.3.18",
"tslib": "^2.0.0"
},
"devDependencies": {
"@testing-library/react": "^11.1.2",
"@types/react": "^16.9.56",
"eslint": "7.4.0",
"eslint-config-molindo": "5.0.1",
"next": "^10.0.2",
"react": "^17.0.0",
"react-dom": "^17.0.0"
"react-dom": "^17.0.0",
"tsdx": "^0.14.1",
"tslib": "^2.0.3",
"typescript": "^4.1.2"
},
"engines": {
"node": ">=10"
}
}

@@ -5,32 +5,173 @@ # next-intl

TODO
Minimal, but complete solution for managing translations in Next.js apps.
short icu guide
## The problem
https://formatjs.io/docs/core-concepts/icu-syntax
Next.js has built-in support for [internationalized routing](https://nextjs.org/docs/advanced-features/i18n-routing), but doesn't have an opinion about how you should handle your translations.
same api for react attributes and children
## This solution
make sure you have polyfills
This is my attempt at providing a minimal, but complete solution that fills in the missing pieces.
cache constructor with ast?
```jsx
function LatestFollower({user}) {
const t = useTranslations('LatestFollower');
// number (https://github.com/unicode-org/icu/blob/master/docs/userguide/format_parse/numbers/skeletons.md#examples)
date https://formatjs.io/docs/intl-messageformat#datetime-skeleton
select https://formatjs.io/docs/core-concepts/icu-syntax/#select-format
get rid of key for rich text?
return (
<>
<Text>{t('latestFollower', {username: user.name})}</Text>
<IconButton aria-label={t('followBack')} icon={<FollowIcon />} />
</>
);
}
```
// optional component name – return all
// otherwise - componentize
```js
// en.json
{
"LatestFollower": {
"latestFollower": "{username} started following you",
"followBack": "Follow back"
}
}
```
typically structure by components
## Features
biggest strength of this library is that it's hooks only. therefore the same API for attributes as well as in children
- Based on battle-tested building blocks from [Format.JS](https://formatjs.io/) (used by `react-intl`), this library is a thin wrapper around high-quality APIs for i18n.
- I18n is really essential for usability, therefore this library doesn't compromise on flexibility and never leaves you behind when you need to fine tune a translation. Messages use the proven [ICU syntax](https://formatjs.io/docs/core-concepts/icu-syntax).
- The bundle size comes in at [32.2kb (9.2kb gzipped)](https://bundlephobia.com/result?p=next-intl) which is the tradeoff that's necessary for the flexibility of the library.
- A hooks-only API ensures that you can use the same API for `children` as well as for attributes which expect strings.
- Integration with Next.js ensures only the least amount of configuration is necessary.
cache values as well?
separate repo?
## Installation
TODO:
- Pass currency to number?
- Relative time
- Check other features of react-intl
1. Install `next-intl` in your project
2. Add the provider in `_app.js`
```jsx
import {NextIntlProvider} from 'next-intl';
import NextApp from 'next/app';
export default function App({Component, messages, pageProps}) {
return (
<NextIntlProvider messages={messages}>
<Component {...pageProps} />
</NextIntlProvider>
);
}
App.getInitialProps = async function getInitialProps(context) {
const {locale} = context.router;
// You can get the messages from anywhere you like, but the recommended
// pattern is to put them in JSON files separated by language and read
// the desired one based on the `locale` received from Next.js. You
// can also separate your messages further (e.g. by page) and read
// them based on the current route.
const messages = locale ? require(`messages/${locale}.json`) : undefined
return {...(await NextApp.getInitialProps(context)), messages};
};
```
3. Based on the features you need and the browsers you support, you might have to provide [polyfills](https://formatjs.io/docs/polyfills).
4. Use translations in your components!
## Usage
```js
// en.json
{
// The recommended approach is to group messages by components.
"Component": {
"static": "Hello",
// See https://formatjs.io/docs/core-concepts/icu-syntax/#simple-argument
"interpolation": "Hello {name}",
// See https://formatjs.io/docs/core-concepts/icu-syntax/#number-type
"number": "{price, number, ::currency/EUR}",
// See https://formatjs.io/docs/intl-messageformat#datetime-skeleton
"date": "{now, date, medium}",
// See https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format
"plural": "You have {numMessages, plural, =0 {no messages} =1 {one message} other {# messages}}.",
// See https://formatjs.io/docs/core-concepts/icu-syntax/#select-format
"select": "{gender, select, male {He} female {She} other {They}} is online.",
// See https://formatjs.io/docs/core-concepts/icu-syntax/#selectordinal-format
"selectordinal": "It's my cat's {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} birthday!",
// See https://formatjs.io/docs/core-concepts/icu-syntax/#rich-text-formatting
"richText": "This is <important>important</important>",
// Messages can be used in attributes
"attributeUrl": "https://example.com",
// Use nesting to provide more structure
"nested": {
"label": "Nested"
}
},
// You don't have to group messages by components. Use whatever suits your use case.
"generic": {
"cancel": "Cancel"
},
// You can also put your components behind namespaces.
"fancyComponents": {
"FancyComponent": {
"hello": "Hello"
}
}
}
```
```js
function Component() {
const t = useTranslations('Component');
return (
<p>{t('static')}</p>
<p>{t('interpolation', {name: 'Jane'})}</p>
<p>{t('number', {price: 31918.231})}</p>
<p>{t('date', {date: new Date('2020-11-20T10:36:01.516Z')})}</p>
<p>{t('plural', {date: new Date('2020-11-20T10:36:01.516Z')})}</p>
<p>{t('selectordinal', {year: 1})}</p>
<p>{t('richText', important: (children: ReactNode) => <b key="important">{children}</b>)}</p>
// TypeScript note: You have to cast the attribute to a string, since it
// can potentially return a `ReactNode`: `String(t('attributeUrl'))`
<a href={t('attributeUrl')}>Link</a>
<p>{t('nested.label')}</p>
);
}
function AllTranslations() {
// You can get all translations if you omit the namespace path.
const t = useTranslations();
}
function FancyComponent() {
// Or you can get messages from a nested namespace. The way the library works
// is that there's a static path of the messages that is resolved in the hook
// and should supply all necessary translations for the component. The remaining
// hierarchy can be resolved by passing the respective path to the `t` function.
const t = useTranslations('fancyComponents.FancyComponent');
}
```
## Tradeoffs
- All relevant translations for the components need to be supplied to the provider – there's no concept of lazy loading translations. If your app has a significant number of messages, the page-based approach of Next.js allows you to only provide the minimum of necessary messages based on the route. If you split your components by features, it might make sense to split your translation files the same way. Ideally a build-time plugin would take care of creating message bundles based on the components used on a page (this would have to include potentially lazy loaded components as well though).
- There are smaller libraries for internationalisation, but they typically cover less features than Format.JS. However if your performance budget doesn't allow for the size of this library, you might be better off with an alternative.
## TODO
- get rid of key for rich text?
- cache format result?
- separate repo?
- Pass currency to number? (if currency is sensitive to locale, use the messages)
- Relative time
- Check other features of react-intl

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet