next-intl 4.14.2 β 4.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ Internationalization (i18n) is an essential part of the user experience, therefo
|
|
|
24
24
|
- π **Next.js-native and performance-obsessed**: App Router, Server Components, static renderingβpick the right tool for the right job, next-intl works everywhere.
|
|
25
25
|
- π **Internationalized routing**: Provide unique pathnames per language and optionally localize pathnames for search engine optimization.
|
|
26
26
|
|
|
27
|
+
[β Read the docs](https://next-intl.dev)
|
|
28
|
+
|
|
27
29
|
## What does it look like?
|
|
28
30
|
|
|
29
31
|
```jsx
|
|
@@ -58,7 +60,35 @@ export default function UserProfile({user}) {
|
|
|
58
60
|
}
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
## Lint your messages
|
|
64
|
+
|
|
65
|
+
As an app grows, messages may drift and become inconsistent.
|
|
66
|
+
|
|
67
|
+
A companion tool, [`eloqnt/cli`](https://cli.eloqnt.dev/docs), catches this by analyzing your source code and messages statically:
|
|
68
|
+
|
|
69
|
+
```console
|
|
70
|
+
$ eloqnt lint
|
|
71
|
+
|
|
72
|
+
messages/de.json
|
|
73
|
+
β
|
|
74
|
+
β "UserProfile.title": "Dein Profil"
|
|
75
|
+
β ββ¬ββββββββββ
|
|
76
|
+
β β°β Inconsistent ICU arguments: missing {firstName} (inconsistent-args)
|
|
77
|
+
β
|
|
78
|
+
β "UserProfile.membership": "Member since {memberSince, date, short}"
|
|
79
|
+
β ββ¬ββββββββββββββββββββββ
|
|
80
|
+
β β°β Missing translation for de (missing-translation)
|
|
81
|
+
|
|
82
|
+
β 1 error
|
|
83
|
+
! 1 warning
|
|
84
|
+
|
|
85
|
+
β Rule details: https://cli.eloqnt.dev/docs/lint-rules/<rule>
|
|
86
|
+
β Run `eloqnt translate` to fill in 1 missing translation
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
It can optionally also fill in missing translations with [`eloqnt translate`](https://cli.eloqnt.dev/docs/cli/translate), using your source code as context.
|
|
90
|
+
|
|
91
|
+
---
|
|
62
92
|
|
|
63
93
|
<div align="center">
|
|
64
94
|
<a href="https://next-intl.dev/redirect?href=https://crowdin.com" target="_blank">
|
|
@@ -139,7 +139,7 @@ function formatPathnameTemplate(template, params) {
|
|
|
139
139
|
template = template.replace(/\[\[/g, '[').replace(/\]\]/g, ']');
|
|
140
140
|
let result = template;
|
|
141
141
|
Object.entries(params).forEach(([key, value]) => {
|
|
142
|
-
result = result.replace(`[${key}]`, value);
|
|
142
|
+
result = result.replace(`[${key}]`, () => value);
|
|
143
143
|
});
|
|
144
144
|
return result;
|
|
145
145
|
}
|
|
@@ -51,7 +51,7 @@ function compileLocalizedPathname({
|
|
|
51
51
|
regexp = `\\[${key}\\]`;
|
|
52
52
|
replacer = String(paramValue);
|
|
53
53
|
}
|
|
54
|
-
compiled = compiled.replace(new RegExp(regexp, 'g'), replacer);
|
|
54
|
+
compiled = compiled.replace(new RegExp(regexp, 'g'), () => replacer);
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -133,8 +133,14 @@ function getRoute(locale, pathname, pathnames) {
|
|
|
133
133
|
function getBasePath(pathname, windowPathname = window.location.pathname) {
|
|
134
134
|
if (pathname === '/') {
|
|
135
135
|
return windowPathname;
|
|
136
|
+
} else if (windowPathname.endsWith(pathname)) {
|
|
137
|
+
// Only strip the trailing occurrence: the pathname can also
|
|
138
|
+
// appear inside the base path itself (e.g. `/dashboard/dash`)
|
|
139
|
+
return windowPathname.slice(0, -pathname.length);
|
|
136
140
|
} else {
|
|
137
|
-
|
|
141
|
+
// Unexpected, since the window pathname should always end with
|
|
142
|
+
// the pathname. Assuming no base path is safe though.
|
|
143
|
+
return '';
|
|
138
144
|
}
|
|
139
145
|
}
|
|
140
146
|
function applyPathnamePrefix(pathname, locale, routing, force) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{normalizeTrailingSlash as e,getSortedPathnames as t,matchesPathname as n,prefixPathname as r,getLocalePrefix as o,templateToRegex as c,getLocalizedTemplate as i}from"../shared/utils.js";function s(e,r,o){const c=t(Object.keys(e));for(const t of c){const c=e[t];if("string"==typeof c){if(n(c,r))return[void 0,t]}else{const s=Object.entries(c),f=s.findIndex((([e])=>e===o));f>0&&s.unshift(s.splice(f,1)[0]);for(const[o]of s){const c=i(e[t],o,t);if(n(c,r))return[o,t]}}}for(const t of Object.keys(e))if(n(t,r))return[void 0,t];return[void 0,void 0]}function f(t,n,r,o){let c="";return c+=p(r,d(n,t)),c=e(c),c}function l(t,n,r){t.endsWith("/")||(t+="/");const o=u(n,r),c=new RegExp(`^(${o.map((([,e])=>e.replaceAll("/","\\/"))).join("|")})/(.*)`,"i"),i=t.match(c);let s=i?"/"+i[2]:t;return"/"!==s&&(s=e(s)),s}function u(e,t,n=!0){const r=e.map((e=>[e,o(e,t)]));return n&&r.sort(((e,t)=>t[1].length-e[1].length)),r}function a(e,t,n,r){const o=u(t,n);r&&o.sort((([e],[t])=>{if(e===r.defaultLocale)return-1;if(t===r.defaultLocale)return 1;const n=r.locales.includes(e),o=r.locales.includes(t);return n&&!o?-1:!n&&o?1:0}));for(const[t,n]of o){let r,o;if(e===n||e.startsWith(n+"/"))r=o=!0;else{const t=e.toLowerCase(),c=n.toLowerCase();(t===c||t.startsWith(c+"/"))&&(r=!1,o=!0)}if(o)return{locale:t,prefix:n,matchedPrefix:e.slice(0,n.length),exact:r}}}function d(t,n){const r=e(n),o=e(t),i=c(o).exec(r);if(!i)return;const s={},f=o.match(/\[([^\]]+)\]/g)??[];for(let e=1;e<i.length;e++){const t=f[e-1];if(!t)continue;const n=t.replace(/[[\]]/g,""),r=i[e]??"";s[n]=r}return s}function p(e,t){if(!t)return e;let n=e=e.replace(/\[\[/g,"[").replace(/\]\]/g,"]");return Object.entries(t).forEach((([e,t])=>{n=n.replace(`[${e}]`,t)})),n}function g(e,t,n){let o=e;return t&&(o=r(t,o)),n&&(o+=n),o}function h(e){return e.get("x-forwarded-host")??e.get("host")??void 0}function x(e,t){return t.defaultLocale===e||t.locales.includes(e)}function m(e,t,n){let r;return e&&x(t,e)&&(r=e),r||(r=n.find((e=>e.defaultLocale===t))),r||(r=n.find((e=>e.locales.includes(t)))),r}function j(t,n){return e(n+t)}function L(e){return`/${e}`}function v(e){return e.replace(/\\/g,"%5C").replace(/[\t\n\r]/g,"").replace(/\/+/g,"/")}export{j as applyBasePath,g as formatPathname,p as formatPathnameTemplate,f as formatTemplatePathname,m as getBestMatchingDomain,h as getHost,s as getInternalTemplate,L as getLocaleAsPrefix,u as getLocalePrefixes,l as getNormalizedPathname,a as getPathnameMatch,d as getRouteParams,x as isLocaleSupportedOnDomain,v as sanitizePathname};
|
|
1
|
+
import{normalizeTrailingSlash as e,getSortedPathnames as t,matchesPathname as n,prefixPathname as r,getLocalePrefix as o,templateToRegex as c,getLocalizedTemplate as i}from"../shared/utils.js";function s(e,r,o){const c=t(Object.keys(e));for(const t of c){const c=e[t];if("string"==typeof c){if(n(c,r))return[void 0,t]}else{const s=Object.entries(c),f=s.findIndex((([e])=>e===o));f>0&&s.unshift(s.splice(f,1)[0]);for(const[o]of s){const c=i(e[t],o,t);if(n(c,r))return[o,t]}}}for(const t of Object.keys(e))if(n(t,r))return[void 0,t];return[void 0,void 0]}function f(t,n,r,o){let c="";return c+=p(r,d(n,t)),c=e(c),c}function l(t,n,r){t.endsWith("/")||(t+="/");const o=u(n,r),c=new RegExp(`^(${o.map((([,e])=>e.replaceAll("/","\\/"))).join("|")})/(.*)`,"i"),i=t.match(c);let s=i?"/"+i[2]:t;return"/"!==s&&(s=e(s)),s}function u(e,t,n=!0){const r=e.map((e=>[e,o(e,t)]));return n&&r.sort(((e,t)=>t[1].length-e[1].length)),r}function a(e,t,n,r){const o=u(t,n);r&&o.sort((([e],[t])=>{if(e===r.defaultLocale)return-1;if(t===r.defaultLocale)return 1;const n=r.locales.includes(e),o=r.locales.includes(t);return n&&!o?-1:!n&&o?1:0}));for(const[t,n]of o){let r,o;if(e===n||e.startsWith(n+"/"))r=o=!0;else{const t=e.toLowerCase(),c=n.toLowerCase();(t===c||t.startsWith(c+"/"))&&(r=!1,o=!0)}if(o)return{locale:t,prefix:n,matchedPrefix:e.slice(0,n.length),exact:r}}}function d(t,n){const r=e(n),o=e(t),i=c(o).exec(r);if(!i)return;const s={},f=o.match(/\[([^\]]+)\]/g)??[];for(let e=1;e<i.length;e++){const t=f[e-1];if(!t)continue;const n=t.replace(/[[\]]/g,""),r=i[e]??"";s[n]=r}return s}function p(e,t){if(!t)return e;let n=e=e.replace(/\[\[/g,"[").replace(/\]\]/g,"]");return Object.entries(t).forEach((([e,t])=>{n=n.replace(`[${e}]`,(()=>t))})),n}function g(e,t,n){let o=e;return t&&(o=r(t,o)),n&&(o+=n),o}function h(e){return e.get("x-forwarded-host")??e.get("host")??void 0}function x(e,t){return t.defaultLocale===e||t.locales.includes(e)}function m(e,t,n){let r;return e&&x(t,e)&&(r=e),r||(r=n.find((e=>e.defaultLocale===t))),r||(r=n.find((e=>e.locales.includes(t)))),r}function j(t,n){return e(n+t)}function L(e){return`/${e}`}function v(e){return e.replace(/\\/g,"%5C").replace(/[\t\n\r]/g,"").replace(/\/+/g,"/")}export{j as applyBasePath,g as formatPathname,p as formatPathnameTemplate,f as formatTemplatePathname,m as getBestMatchingDomain,h as getHost,s as getInternalTemplate,L as getLocaleAsPrefix,u as getLocalePrefixes,l as getNormalizedPathname,a as getPathnameMatch,d as getRouteParams,x as isLocaleSupportedOnDomain,v as sanitizePathname};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getSortedPathnames as e,matchesPathname as n,isLocalizableHref as t,prefixPathname as r,normalizeTrailingSlash as o,getLocalizedTemplate as a,getLocalePrefix as i}from"../../shared/utils.js";function c(e){return"string"==typeof e?{pathname:e}:e}function s(e){function n(e){return String(e)}const t=new URLSearchParams;for(const[r,o]of Object.entries(e))Array.isArray(o)?o.forEach((e=>{t.append(r,n(e))})):t.set(r,n(o));return"?"+t.toString()}function f({pathname:e,locale:n,params:t,pathnames:r,query:i}){function c(e){const c=r[e];let f;if(c){const r=a(c,n,e);f=r,t&&Object.entries(t).forEach((([e,n])=>{let t,r;Array.isArray(n)?(t=`(\\[)?\\[...${e}\\](\\])?`,r=n.map((e=>String(e))).join("/")):(t=`\\[${e}\\]`,r=String(n)),f=f.replace(new RegExp(t,"g"),r)})),f=f.replace(/\[\[\.\.\..+\]\]/g,""),f=function(e){return new URL(e,"http://l").pathname}(f)}else f=e;return f=o(f),i&&(f+=s(i)),f}if("string"==typeof e)return c(e);{const{pathname:n,...t}=e;return{...t,pathname:c(n)}}}function l(t,r,o){const i=e(Object.keys(o)),c=decodeURI(r);for(const e of i){const r=o[e];if("string"==typeof r){if(n(r,c))return e}else if(n(a(r,t,e),c))return e}return r}function u(e,n=window.location.pathname){return"/"===e?n:n.
|
|
1
|
+
import{getSortedPathnames as e,matchesPathname as n,isLocalizableHref as t,prefixPathname as r,normalizeTrailingSlash as o,getLocalizedTemplate as a,getLocalePrefix as i}from"../../shared/utils.js";function c(e){return"string"==typeof e?{pathname:e}:e}function s(e){function n(e){return String(e)}const t=new URLSearchParams;for(const[r,o]of Object.entries(e))Array.isArray(o)?o.forEach((e=>{t.append(r,n(e))})):t.set(r,n(o));return"?"+t.toString()}function f({pathname:e,locale:n,params:t,pathnames:r,query:i}){function c(e){const c=r[e];let f;if(c){const r=a(c,n,e);f=r,t&&Object.entries(t).forEach((([e,n])=>{let t,r;Array.isArray(n)?(t=`(\\[)?\\[...${e}\\](\\])?`,r=n.map((e=>String(e))).join("/")):(t=`\\[${e}\\]`,r=String(n)),f=f.replace(new RegExp(t,"g"),(()=>r))})),f=f.replace(/\[\[\.\.\..+\]\]/g,""),f=function(e){return new URL(e,"http://l").pathname}(f)}else f=e;return f=o(f),i&&(f+=s(i)),f}if("string"==typeof e)return c(e);{const{pathname:n,...t}=e;return{...t,pathname:c(n)}}}function l(t,r,o){const i=e(Object.keys(o)),c=decodeURI(r);for(const e of i){const r=o[e];if("string"==typeof r){if(n(r,c))return e}else if(n(a(r,t,e),c))return e}return r}function u(e,n=window.location.pathname){return"/"===e?n:n.endsWith(e)?n.slice(0,-e.length):""}function p(e,n,o,a){const{mode:c}=o.localePrefix;let s;if(void 0!==a)s=a;else if(t(e)){const e=o.domains?.find((e=>e.locales.includes(n))),t=e?.localePrefix||c;"always"===t?s=!0:"as-needed"===t&&(s=e?n!==e.defaultLocale:n!==o.defaultLocale)}return s?r(i(n,o.localePrefix),e):e}export{p as applyPathnamePrefix,f as compileLocalizedPathname,u as getBasePath,l as getRoute,c as normalizeNameOrNameWithParams,s as serializeSearchParams};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-intl",
|
|
3
|
-
"version": "4.14.
|
|
3
|
+
"version": "4.14.4",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"author": "Jan Amann <jan@amann.work>",
|
|
6
6
|
"funding": [
|
|
@@ -130,14 +130,14 @@
|
|
|
130
130
|
"@formatjs/intl-localematcher": "^0.8.1",
|
|
131
131
|
"@parcel/watcher": "^2.4.1",
|
|
132
132
|
"@swc/core": "~1.16.0",
|
|
133
|
-
"icu-minify": "^4.14.
|
|
133
|
+
"icu-minify": "^4.14.4",
|
|
134
134
|
"negotiator": "^1.0.0",
|
|
135
|
-
"next-intl-swc-plugin-extractor": "4.14.
|
|
136
|
-
"use-intl": "^4.14.
|
|
135
|
+
"next-intl-swc-plugin-extractor": "4.14.4",
|
|
136
|
+
"use-intl": "^4.14.4"
|
|
137
137
|
},
|
|
138
138
|
"peerDependencies": {
|
|
139
139
|
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
140
140
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
|
|
141
141
|
},
|
|
142
|
-
"gitHead": "
|
|
142
|
+
"gitHead": "8267c8f16d6c503abff7a3d909a89a0c6c862049"
|
|
143
143
|
}
|