سهل i18n لـ next.js +10
البرنامج المساعد التالي + I18N API
ملحوظة
نحن نعمل مع الإصدار 3.0.0 من النقل التالي. في الأشهر الأخيرة ، كنا نركز بشدة على بريسا . لقد مر وقت طويل منذ الإصدار الأخير ، لكننا لم ننسى المترتبة التالية. نحن نعمل على إصدار جديد من شأنه أن يجلب العديد من التحسينات والميزات الجديدة. نحن متحمسون للغاية لمشاركته معكم جميعًا.

الهدف الرئيسي من هذه المكتبة هو الحفاظ على الترجمات البسيطة قدر الإمكان في بيئة Next.js.
يحتوي المترجم التالي على جزأين: Next.js Plugin + I18N API .
سمات

في ملف التكوين ، يمكنك تحديد كل صفحة تحتاجها مساحات الأسماء:
I18N.JSON
{
"pages" : {
"*" : [ "common" ] ,
"/" : [ "home" ] ,
"/cart" : [ "cart" ] ,
"/content/[slug]" : [ "content" ] ,
"rgx:^/account" : [ "account" ]
}
// rest of config here...
}اقرأ هنا حول كيفية إضافة مساحات الأسماء JSON.
يضمن النقل التالي أن كل صفحة لها فقط مساحات أسماءها مع اللغة الحالية. لذلك إذا كان لدينا 100 لغ ، فسيتم تحميل واحد فقط.
من أجل القيام بذلك ، نستخدم محمل WebPack يقوم بتحميل ملفات الترجمة اللازمة داخل طرق Next.js ( GetStaticProps أو getServersIdeProps أو getInitialProps ). إذا كان لديك إحدى هذه الطرق الموجودة بالفعل على صفحتك ، فسيستخدم محمل WebPack طريقتك الخاصة ، ولكن الافتراضيات التي ستستخدمها هي:
getStaticProps . هذه هي الطريقة الافتراضية المستخدمة في معظم الصفحات ، ما لم تكن صفحة محددة في النقطتين التاليتين. هذا من أجل الأداء ، وبالتالي يتم إجراء الحسابات في وقت البناء بدلاً من وقت الطلب.getServerSideProps . هذه هي الطريقة الافتراضية للصفحات الديناميكية مثل [slug].js أو [...catchall].js . هذا لأنه بالنسبة لهذه الصفحات ، من الضروري تحديد getStaticPaths وليس هناك معرفة بكيفية أن تكون الرخويات لكل لغة. وبالمثل ، كيف يتم ذلك افتراضيًا ، فقط تكتب GetStaticPaths ، فسيستخدم بالفعل GetStaticProps لتحميل الترجمات.getInitialProps . هذه هي الطريقة الافتراضية لهذه الصفحات التي تستخدم مخصصًا . هذا من أجل تجنب النزاعات لأن المخصص يمكن أن يكتب فوق getInitialProps . هذه العملية برمتها شفافة ، لذا في صفحاتك ، يمكنك استهلاك خطاف useTranslation مباشرة لاستخدام مساحات الأسماء ، ولا تحتاج إلى فعل أي شيء آخر.
إذا كنت تستخدم لسبب ما getInitialProps في ملف _app.js الخاص بك ، فلن يتم تحميل الترجمات إلا في getInitialProps من _app.js . نوصي أنه لأسباب لا تستخدم هذا النهج لأسباب التحسين ما لم يكن ضروريًا للغاية.
yarn add next-translate إن next-translate-plugin هو أداة تتيح للمطورين التعامل مع الترجمات بكفاءة على أساس كل صفحة أثناء عملية الإنشاء. إنه متميز عن حزمة next-translate ، والتي تتيح للمطورين الوصول إلى الترجمات في الكود الذي تحتاجه. يعمل المكون الإضافي عن طريق تحليل جميع الصفحات ، والبحث عن الترجمات وإعادة كتابة ملف الصفحة إضافة الترجمات إليه. هذا يجعل البرنامج المساعد حلاً أكثر كفاءة ومرونة للتعامل مع الترجمات ضمن تطبيق NEXT.JS. يوصى بتثبيت المكون الإضافي باعتباره devDependency.
yarn add next-translate-plugin -Dفي ملف next.config.js الخاص بك:
const nextTranslate = require ( 'next-translate-plugin' )
module . exports = nextTranslate ( ) أو إذا كان لديك ملف NEXT.CONFIG.JS بالفعل وترغب في الاحتفاظ بالتغييرات فيه ، فقم بتمرير كائن التكوين إلى the nextTranslate() . على سبيل المثال بالنسبة لـ WebPack ، يمكنك القيام بذلك على هذا النحو:
const nextTranslate = require ( 'next-translate-plugin' )
module . exports = nextTranslate ( {
webpack : ( config , { isServer , webpack } ) => {
return config ;
}
} ) إضافة ملف التكوين i18n.json (أو i18n.js مع module.exports ) في جذر المشروع. يجب أن يكون لكل صفحة مساحات أسمائها. ألقِ نظرة عليه في قسم التكوين لمزيد من التفاصيل.
{
"locales" : [ " en " , " ca " , " es " ],
"defaultLocale" : " en " ,
"pages" : {
"*" : [ " common " ],
"/" : [ " home " , " example " ],
"/about" : [ " about " ]
}
}في ملف التكوين ، يمكنك استخدام كل من التكوين الذي حددناه هنا والميزات الخاصة حول تدويل Next.js 10.
بشكل افتراضي ، يتم تحديد مساحات الأسماء على دليل الجذر /اللغات بهذه الطريقة:
/لغات
.
├── ca
│ ├── common.json
│ └── home.json
├── en
│ ├── common.json
│ └── home.json
└── es
├── common.json
└── home.json يطابق كل اسم ملف مساحة الاسم المحددة في خاصية تكوين pages ، بينما يجب أن يكون كل محتوى ملف مشابهًا لهذا:
{
"title" : " Hello world " ,
"variable-example" : " Using a variable {{count}} "
}ومع ذلك ، يمكنك استخدام وجهة أخرى لحفظ ملفات مساحات الأسماء الخاصة بك باستخدام خاصية تكوين LoadLocaleFrom:
I18N.JS
{
// ...rest of config
"loadLocaleFrom" : ( lang , ns ) =>
// You can use a dynamic import, fetch, whatever. You should
// return a Promise with the JSON file.
import ( `./myTranslationsFiles/ ${ lang } / ${ ns } .json` ) . then ( ( m ) => m . default ) ,
}ثم ، استخدم الترجمات في الصفحة ومكوناتها:
صفحات/مثال
import useTranslation from 'next-translate/useTranslation'
export default function ExamplePage ( ) {
const { t , lang } = useTranslation ( 'common' )
const example = t ( 'variable-example' , { count : 42 } )
return < div > { example } </ div > // <div>Using a variable 42</div>
}يمكنك استهلاك الترجمات مباشرة على صفحاتك ، لا داعي للقلق بشأن تحميل ملفات مساحات الأسماء يدويًا في كل صفحة. يقوم المكون الإضافي بالترسل التالي إلى تحميل مساحات الأسماء التي تحتاجها الصفحة فقط مع اللغة الحالية فقط.
في ملف التكوين ، يمكنك استخدام كل من التكوين الذي حددناه هنا والميزات الخاصة حول تدويل Next.js 10.
| خيار | وصف | يكتب | تقصير |
|---|---|---|---|
defaultLocale | ISO من اللغة الافتراضية ("EN" كما الافتراضي). | string | "en" |
locales | مجموعة مع جميع اللغات لاستخدامها في المشروع. | string[] | [] |
loadLocaleFrom | قم بتغيير طريقة تحميل مساحات الأسماء. | function التي تعيد Promise مع JSON . | بشكل افتراضي هو تحميل مساحات الأسماء من دليل الجذر. |
pages | كائن يحدد مساحات الأسماء المستخدمة في كل صفحة. مثال على الكائن: {"/": ["home", "example"]} . لإضافة مساحات أسماء إلى جميع الصفحات ، يجب عليك استخدام المفتاح "*" ، على سبيل المثال: {"*": ["common"]} . من الممكن أيضًا استخدام regex باستخدام rgx: On Front: {"rgx:/form$": ["form"]} . يمكنك أيضًا استخدام وظيفة بدلاً من صفيف ، لتوفير بعض مساحات الأسماء اعتمادًا على بعض القواعد ، على سبيل المثال: { "/": ({ req, query }) => query.type === 'example' ? ['example'] : []} | Object<string[] or function> | {} |
logger | وظيفة لتسجيل المفاتيح المفقودة في التطوير والإنتاج. إذا كنت تستخدم i18n.json كملف التكوين ، فيجب عليك تغييره إلى i18n.js | function | بشكل افتراضي ، فإن المسجل هو وظيفة تقوم بإجراء console.warn فقط في التطوير. |
loggerEnvironment | سلسلة لتحديد ما إذا كان يجب تشغيل المسجل في المتصفح ، في العقدة أو كليهما | "node" | "browser" | "both" | "browser" |
logBuild | كل صفحة لها سجل يشير إلى: مساحات الأسماء واللغة الحالية والطريقة المستخدمة لتحميل مساحات الأسماء. مع هذا يمكنك تعطيله. | Boolean | true |
loader | إذا كنت ترغب في تعطيل محمل WebPack وتحميل مساحات الأسماء في كل صفحة يدويًا ، فإننا نمنحك الفرصة للقيام بذلك عن طريق تعطيل هذا الخيار. | Boolean | true |
interpolation | قم بتغيير المحدد الذي يستخدم للاستيفاء. | {prefix: string; suffix: string, formatter: function } | {prefix: '{{', suffix: '}}'} |
keySeparator | تغيير الفاصل الذي يستخدم للمفاتيح المتداخلة. تعيين على false لتعطيل مفاتيح التعشيش في ملفات ترجمة JSON. يمكن أن تكون مفيدة إذا كنت ترغب في استخدام النص الطبيعي كمفاتيح. | string | false | '.' |
nsSeparator | شار لتقسيم مساحة الاسم من المفتاح. يجب عليك تعيينها على false إذا كنت تريد استخدام النص الطبيعي كمفاتيح. | string | false | ':' |
defaultNS | مساحة الاسم الافتراضية المستخدمة إن لم يتم نقلها إلى useTranslation أو في مفتاح الترجمة. | string | undefined |
staticsHoc | لا تستخدم HOCs التي لدينا في API (AppWithi18n) ، لا تستخدم إلى حد كبير للبعوث من أجل عدم تضمين KB أكثر من اللازم (يتم استخدام القيم الثابتة عن getInitialProps في الصفحات نادرًا ما يتم استخدامها) . إذا كان لديك أي تعارض مع الإحصائيات ، فيمكنك إضافة مواد لا تتفاعل (أو أي بديل آخر) هنا. انظر مثال. | Function | null |
extensionsRgx | قم بتغيير regex المستخدمة بواسطة محمل WebPack للعثور على صفحات Next.js. | Regex | /.(tsx|ts|js|mjs|jsx)$/ |
revalidate | إذا كنت ترغب في الحصول على إعادة صياغة افتراضية في كل صفحة ، فإننا نمنحك الفرصة للقيام بذلك عن طريق تمرير رقم لتحديده. لا يزال بإمكانك تحديد getStaticProps على صفحة بمبلغ مختلف إعادة التحفيز وتجاوز هذا التجاوز الافتراضي. | Number | إذا لم تحدده ، فلن يكون للصفحات افتراضيًا أي شيء. |
pagesInDir | my-app/pages قمت بالركض next ./my-app . | String | إذا لم تحدده ، فسيتم البحث عن الصفحات بشكل افتراضي في الأماكن الكلاسيكية مثل pages والصفحات src/pages . |
localesToIgnore | أشر إلى هذه اللغات التي يجب تجاهلها عندما تقوم ببلاغ اللغة الافتراضية باستخدام برامج وسيطة (في التالي +12 ، تعلم كيفية القيام بذلك) | Array<string> | ['default'] |
allowEmptyStrings | تغيير كيفية معالجة السلاسل الفارغة المترجمة. إذا تم حذفه أو تم تمريره كما هو صحيح ، فإنه يعيد سلسلة فارغة. إذا تم تمريره كخطأ ، فإن إرجاع اسم المفتاح نفسه (بما في ذلك NS). | Boolean | true |
الحجم : ~ 150b؟
هذا الخطاف هو الطريقة الموصى بها لاستخدام الترجمات في صفحاتك / مكوناتك.
مثال:
import React from 'react'
import useTranslation from 'next-translate/useTranslation'
export default function Description ( ) {
const { t , lang } = useTranslation ( 'ns1' ) // default namespace (optional)
const title = t ( 'title' )
const titleFromOtherNamespace = t ( 'ns2:title' )
const description = t `description` // also works as template string
const example = t ( 'ns2:example' , { count : 3 } ) // and with query params
const exampleDefault = t ( 'ns:example' , { count : 3 } , { default : "The count is: {{count}}." } ) // and with default translation
return (
< >
< h1 > { title } </ h1 >
< p > { description } </ p >
< p > { example } </ p >
< >
)
} وظيفة t :
i18nKey . مماثلة من useTranslation ولكن دون أن تكون خطاف. هذا المساعد يعمل فقط في تطبيق Dir .
const { t , lang } = createTranslation ( 'ns1' ) // default namespace (optional)
const title = t ( 'title' )الحجم : ~ 560B؟
إنه بديل لخطاف useTranslation ، ولكن في مخصص لهذه المكونات التي لا تعمل. (غير موصى به ، من الأفضل استخدام خطاف useTranslation .) .
يرجع المخصص withTranslation مكونًا مع دعامة إضافية تسمى i18n (Object {t: function ، lang: string}).
مثال:
import React from 'react'
import withTranslation from 'next-translate/withTranslation'
class Description extends React . Component {
render ( ) {
const { t , lang } = this . props . i18n
const description = t ( 'common:description' )
return < p > { description } </ p >
}
}
export default withTranslation ( NoFunctionalComponent ) على غرار useTranslation("common") يمكنك الاتصال withTranslation مع المعلمة الثانية التي تحدد مساحة الاسم الافتراضية لاستخدامها:
export default withTranslation(NoFunctionalComponent, "common")
الحجم : ~ 1.4 كيلو بايت؟
في بعض الأحيان ، نحتاج إلى القيام ببعض الترجمات باستخدام HTML داخل النص (الجريئة ، والروابط ، وما إلى ذلك) ، المكون Trans هو بالضبط ما تحتاجه لهذا. نوصي باستخدام هذا المكون فقط في هذه الحالة ، لحالات أخرى نوصي بشدة باستخدام خطاف useTranslation بدلاً من ذلك.
مثال:
// The defined dictionary entry is like:
// "example": "<0>The number is <1>{{count}}</1></0>",
< Trans
i18nKey = "common:example"
components = { [ < Component /> , < b className = "red" /> ] }
values = { { count : 42 } }
/> أو استخدام components الدعامة ككائن:
// The defined dictionary entry is like:
// "example": "<component>The number is <b>{{count}}</b></component>",
< Trans
i18nKey = "common:example"
components = { {
component : < Component /> ,
b : < b className = "red" /> ,
} }
values = { { count : 42 } }
defaultTrans = "<component>The number is <b>{{count}}</b></component>"
/>i18nKey - سلسلة - مفتاح إدخال i18n (مساحة الاسم: مفتاح)components - صفيف | الكائن - في حالة صفيف كل فهرس يتوافق مع العلامة المحددة <0> / <1> . في حالة الكائن ، يتوافق كل مفتاح مع العلامة المحددة <example> .values - كائن - معاملات الاستعلامfallback - سلسلة | سلسلة [] - اختياري. الاحتياطي i18nkey إذا كان i18nkey لا يتطابق.defaultTrans - سلسلة - الترجمة الافتراضية للمفتاح. إذا تم استخدام مفاتيح العودة ، فسيتم استخدامها فقط بعد استنفاد جميع الاحتياطات.ns - مساحة الاسم التي يجب استخدامها عندما لا يتم تضمين أي منها في i18nKeyreturnObjects - Boolean - احصل على جزء من JSON مع جميع الترجمات. رؤية المزيد. في الحالات التي نحتاج فيها إلى وظيفة المكون Trans ، ولكن نحتاج إلى تشكيلة سلسلة ، بدلاً من إخراج وظيفة t(props.i18nKey) ، هناك أيضًا مكون TransText ، والذي يأخذ دعامة text بدلاً من i18nKey .
text - السلسلة - السلسلة التي (اختياريا) تحتوي على علامات تتطلب الاستيفاءcomponents - صفيف | كائن - هذا يتصرف تمامًا مثل Trans (انظر أعلاه). هذا مفيد بشكل خاص عند رسم الخرائط على إخراج t() مع returnObjects: true :
// The defined dictionary entry is like:
// "content-list": ["List of <link>things</link>", "with <em>tags</em>"]
const contentList = t ( 'someNamespace:content-list' , { } , { returnObjects : true } ) ;
{ contentList . map ( ( listItem : string ) => (
< TransText
text = { listItem }
components = { {
link : < a href = "some-url" /> ,
em : < em /> ,
} }
/>
) }الحجم : ~ 1.5 كيلو بايت؟
يعد مكون DynamicNamespaces مفيدًا لتحميل مساحات الأسماء الديناميكية ، على سبيل المثال ، في الوسائط.
مثال:
import React from 'react'
import Trans from 'next-translate/Trans'
import DynamicNamespaces from 'next-translate/DynamicNamespaces'
export default function ExampleWithDynamicNamespace ( ) {
return (
< DynamicNamespaces namespaces = { [ 'dynamic' ] } fallback = "Loading..." >
{ /* ALSO IS POSSIBLE TO USE NAMESPACES FROM THE PAGE */ }
< h1 >
< Trans i18nKey = "common:title" />
</ h1 >
{ /* USING DYNAMIC NAMESPACE */ }
< Trans i18nKey = "dynamic:example-of-dynamic-translation" />
</ DynamicNamespaces >
)
} تذكر أنه لا ينبغي سرد مساحة الاسم ['dynamic'] على تكوين pages :
pages: {
'/my-page' : [ 'common' ] , // only common namespace
}namespaces - String [] - قائمة مساحات الأسماء الديناميكية للتنزيل - المطلوب .fallback - ReactNode - Fropback لعرض في هذه الأثناء يتم تحميل مساحات الأسماء. - خياري .dynamic - الوظيفة - افتراضيًا ، يستخدم loadlocalefrom في التكوين لتحميل مساحات الأسماء ، ولكن يمكنك تحديد وجهة أخرى. - خياري .الحجم : ~ 1.3 كيلو بايت؟
وظيفة غير متزامنة لتحميل وظيفة t خارج المكونات / الصفحات. إنه يعمل على كل من جانب الخادم وجانب العميل.
على عكس خطاف Usetranslation ، يمكننا استخدام أي مساحة اسم هنا ، لا يجب أن تكون مساحة اسم محددة في تكوين "الصفحات". يقوم بتنزيل مساحة الاسم المشار إليها كمعلمة في وقت التشغيل.
يمكنك تحميل مساحات أسماء متعددة عن طريق إعطاء صفيف كمعلمة ، وفي هذه الحالة ستكون مساحة الاسم الافتراضية هي القبضة.
مثال داخل getStaticProps :
import getT from 'next-translate/getT'
// ...
export async function getStaticProps ( { locale } ) {
const t = await getT ( locale , 'common' )
const title = t ( 'title' )
return { props : { title } }
}مثال داخل طريق API:
import getT from 'next-translate/getT'
export default async function handler ( req , res ) {
const t = await getT ( req . query . __nextLocale , 'common' )
const title = t ( 'title' )
res . statusCode = 200
res . setHeader ( 'Content-Type' , 'application/json' )
res . end ( JSON . stringify ( { title } ) )
}مثال على تحميل مساحات أسماء متعددة:
import getT from 'next-translate/getT'
export default async function handler ( req , res ) {
const t = await getT ( req . query . __nextLocale , [ 'common' , 'errors' ] )
const title = t ( 'title' ) // The default namespace is the first one.
const errorMessage = t ( 'errors:app_error' ) // The default namespace is the first one.
res . statusCode = 200
res . setHeader ( 'Content-Type' , 'application/json' )
res . end ( JSON . stringify ( { title } ) )
}الحجم : ~ 3 كيلو بايت؟
I18nProvider هو مزود سياق يستخدم داخليًا من قبل النقل التالي لتوفير مساحات أسماء الصفحة الحالية ومساحات أسماء الصفحة. لذلك ربما لن تحتاج أبدًا إلى هذا .
ومع ذلك ، فإنه يتعرض لواجهة برمجة التطبيقات لأنه يمكن أن يكون مفيدًا في بعض الحالات. على سبيل المثال ، لاستخدام ترجمات متعددة اللغات في صفحة.
يتراكم I18nProvider مساحات الأسماء ، بحيث يمكنك إعادة تسمية المساحات الجديدة من أجل الحفاظ على المساحات القديمة.
import React from 'react'
import I18nProvider from 'next-translate/I18nProvider'
import useTranslation from 'next-translate/useTranslation'
// Import English common.json
import commonEN from '../../locales/en/common.json'
function PageContent ( ) {
const { t , lang } = useTranslation ( )
console . log ( lang ) // -> current language
return (
< div >
< p > { t ( 'common:example' ) /* Current language */ } </ p >
< p > { t ( 'commonEN:example' ) /* Force English */ } </ p >
</ div >
)
}
export default function Page ( ) {
const { lang } = useTranslation ( )
return (
< I18nProvider lang = { lang } namespaces = { { commonEN } } >
< PageContent />
</ I18nProvider >
)
}الحجم : ~ 3.7 كيلو بايت؟
يستخدم appWithI18n داخليًا بواسطة النقل التالي. لذلك ربما لن تحتاج أبدًا إلى هذا . ومع ذلك ، فإننا نعرضها في واجهة برمجة التطبيقات في حالة تعطيل خيار محمل WebPack ونقرر تحميل مساحات الأسماء يدويًا.
إذا كنت لا ترغب في استخدام محمل WebPack ، فيجب عليك وضع هذا في ملف _app.js الخاص بك (وإنشاء ملف _app.js إذا لم يكن لديك).
مثال:
_app.js
import appWithI18n from 'next-translate/appWithI18n'
import i18nConfig from '../i18n'
function MyApp ( { Component , pageProps } ) {
return < Component { ... pageProps } />
}
// Wrapping your _app.js
export default appWithI18n ( MyApp , {
... i18nConfig ,
// Set to false if you want to load all the namespaces on _app.js getInitialProps
skipInitialProps : true ,
} ) إذا كان skipInitialProps=true ، فيجب عليك أيضًا استخدام المساعد LoadNamesPaces لتحميل مساحات الأسماء يدويًا في كل صفحة.
الحجم : ~ 1.9 كيلو بايت؟
يستخدم loadNamespaces داخليًا بواسطة النقل التالي. لذلك ربما لن تحتاج أبدًا إلى هذا . ومع ذلك ، فإننا نعرضها في واجهة برمجة التطبيقات في حالة تعطيل خيار محمل WebPack ونقرر تحميل مساحات الأسماء يدويًا.
لتحميل مساحات الأسماء ، يجب أن تعيد في صفحاتك الدعائم التي يوفرها المساعد.
import loadNamespaces from 'next-translate/loadNamespaces'
export function getStaticProps ( { locale } ) {
return {
props : {
... ( await loadNamespaces ( { locale , pathname : '/about' } ) ) ,
}
}
} للعمل بشكل جيد ، من الضروري أن يتم لف _app.js الخاص بك مع appwithi18n. أيضا ، خاصية تكوين loadLocaleFrom إلزامية لتحديدها.
نحن ندعم 6 نماذج صيغة الجمع (مأخوذة من صفحة CLDR Clurals) عن طريق الإضافة إلى المفتاح هذه اللاحقة (أو تعشش تحت المفتاح _ بادئة):
_zero_one (المفرد)_two (مزدوج)_few (قول)_many (يستخدم أيضًا للكسور إذا كان لديهم فئة منفصلة)_other (مطلوب - شكل الجمع الجينوي - يستخدم أيضًا إذا كانت اللغة لها شكل واحد فقط)شاهد المزيد من المعلومات حول التجميع هنا .
فقط آخر ، _other ، مطلوب لأنه النموذج الجمع الشائع الوحيد المستخدم في جميع الأماكن.
جميع أشكال الجمع الأخرى تعتمد على اللغة. على سبيل المثال ، لدى اللغة الإنجليزية اثنان فقط: _one و _other (1 Cat مقابل 2 Cats). بعض اللغات لديها المزيد ، مثل الروسية والعربية.
بالإضافة إلى ذلك ، فإننا ندعم أيضًا مطابقة دقيقة من خلال تحديد الرقم ( _0 ، _999 ) وهذا يعمل لجميع اللغات. هنا مثال:
شفرة:
// **Note**: Only works if the name of the variable is {{count}}.
t ( 'cart-message' , { count } )مساحة الاسم:
{
"cart-message_0" : "The cart is empty" , // when count === 0
"cart-message_one" : "The cart has only {{count}} product" , // singular
"cart-message_other" : "The cart has {{count}} products" , // plural
"cart-message_999" : "The cart is full" , // when count === 999
}أو
{
"cart-message" : {
"0" : "The cart is empty" , // when count === 0
"one" : "The cart has only {{count}} product" , // singular
"other" : "The cart has {{count}} products" , // plural
"999" : "The cart is full" , // when count === 999
}
}Intl.PluralRules API متاح فقط للمتصفحات الحديثة ، إذا كنت ترغب في استخدامها في المتصفحات القديمة ، فيجب عليك إضافة Polyfill.
يمكنك تحديد HTML داخل الترجمة بهذه الطريقة:
{
"example-with-html" : " <0>This is an example <1>using HTML</1> inside the translation</0> "
}مثال:
import Trans from 'next-translate/Trans'
// ...
const Component = ( props ) => < p { ... props } />
// ...
< Trans
i18nKey = "namespace:example-with-html"
components = { [ < Component /> , < b className = "red" /> ] }
/ >النتيجة المقدمة:
< p > This is an example < b class =" red " > using HTML </ b > inside the translation </ p > يتوافق كل فهرس من صفيف components مع <index></index> من التعريف.
في مجموعة components ، ليس من الضروري تمرير أطفال كل عنصر. سيتم حساب الأطفال.
في مساحة الاسم ، من الممكن تحديد مفاتيح متداخلة مثل هذا:
{
"nested-example" : {
"very-nested" : {
"nested" : " Nested example! "
}
}
}من أجل استخدامه ، يجب عليك استخدام ". كفاصل هوية:
t `namespace:nested-example.very-nested.nested`من الممكن أيضًا استخدام Array:
{
"array-example" : [
{ "example" : " Example {{count}} " },
{ "another-example" : " Another example {{count}} " }
]
} واحصل على جميع ترجمات الصفيف مع خيار returnObjects :
t ( 'namespace:array-example' , { count : 1 } , { returnObjects : true } )
/*
[
{ "example": "Example 1" },
{ "another-example": "Another example 1" }
]
*/ من الممكن أيضًا الحصول على جميع الترجمات باستخدام keyseparator كمفتاح ، افتراضي هو '.' :
t ( 'namespace:.' , { count : 1 } , { returnObjects : true } )
/*
{
"array-example": [
{ "example": "Example 1" },
{ "another-example": "Another example 1" }
]
}
*/ في حالة عدم وجود ترجمة ، يمكنك تحديد الاحتياطات ( string|string[] ) للبحث عن ترجمات أخرى:
const { t } = useTranslation ( )
const textOrFallback = t (
'ns:text' ,
{ count : 1 } ,
{
fallback : 'ns:fallback' ,
}
)قائمة الاحتياطات:
const { t } = useTranslation ( )
const textOrFallback = t (
'ns:text' ,
{ count : 42 } ,
{
fallback : [ 'ns:fallback1' , 'ns:fallback2' ] ,
}
)في المكون العابر:
< Trans
i18nKey = "ns:example"
components = { [ < Component /> , < b className = "red" /> ] }
values = { { count : 42 } }
fallback = { [ 'ns:fallback1' , 'ns:fallback2' ] } // or string with just 1 fallback
/> يمكنك تنسيق المعلمات باستخدام وظيفة التكوين interpolation.format .
في i18n.js :
const formatters = {
es : new Intl . NumberFormat ( "es-ES" ) ,
en : new Intl . NumberFormat ( "en-EN" ) ,
}
return {
// ...
interpolation : {
format : ( value , format , lang ) => {
if ( format === 'number' ) return formatters [ lang ] . format ( value )
return value
}
}
}في مساحة الاسم الإنجليزية:
{
"example" : " The number is {{count, number}} "
}في مساحة الاسم الإسبانية:
{
"example" : " El número es {{count, number}} "
}استخدام:
t ( 'example' , { count : 33.5 } )عائدات:
The number is 33.5El número es 33,5 من أجل تغيير اللغة الحالية ، يمكنك استخدام Next.js Mavigation (Link and Trouter) تمرير locale prop.
مثال على مكون ChangeLanguage المحتمل باستخدام خطاف useRouter من Next.js :
import React from 'react'
import Link from 'next/link'
import useTranslation from 'next-translate/useTranslation'
import i18nConfig from '../i18n.json'
const { locales } = i18nConfig
export default function ChangeLanguage ( ) {
const { t , lang } = useTranslation ( )
return locales . map ( ( lng ) => {
if ( lng === lang ) return null
return (
< Link href = "/" locale = { lng } key = { lng } >
{ t ( `layout:language-name- ${ lng } ` ) }
</ Link >
)
} )
} يمكنك أيضًا استخدام setLanguage لتغيير اللغة مع الحفاظ على نفس الصفحة.
import React from 'react'
import setLanguage from 'next-translate/setLanguage'
export default function ChangeLanguage ( ) {
return (
< button onClick = { async ( ) => await setLanguage ( 'en' ) } > EN </ button >
)
} هناك طريقة أخرى للوصول إلى قائمة locales لتغيير اللغة وهي استخدام Next.js router يمكن الوصول إلى قائمة locales باستخدام خطاف userouter next.js.
يمكنك تعيين ملف تعريف ارتباط باسم NEXT_LOCALE مع اللغة المعرفة من قبل المستخدم كقيمة ، وبهذه الطريقة يمكن إجبار اللغة.
مثال على الخطاف:
import { useRouter } from 'next/router'
// ...
function usePersistLocaleCookie ( ) {
const { locale , defaultLocale } = useRouter ( )
useEffect ( persistLocaleCookie , [ locale , defaultLocale ] )
function persistLocaleCookie ( ) {
if ( locale !== defaultLocale ) {
const date = new Date ( )
const expireMs = 100 * 24 * 60 * 60 * 1000 // 100 days
date . setTime ( date . getTime ( ) + expireMs )
document . cookie = `NEXT_LOCALE= ${ locale } ;expires= ${ date . toUTCString ( ) } ;path=/`
}
}
} في بعض الحالات ، عندما تكون الصفحة في اللغة الحالية ، قد ترغب في القيام ببعض الاستثناءات التي تعرض بعض النص بلغة أخرى.
في هذه الحالة ، يمكنك تحقيق ذلك باستخدام I18nProvider .
تعلم كيفية القيام بذلك هنا.
يستخدم النقل التالي افتراضيًا دليل العمل الحالي لعملية node.js ( process.cwd() ).
إذا كنت تريد تغييره يمكنك استخدامه:
NEXT_TRANSLATE_PATH . وهو يدعم المسار النسبي والمطلقprocess.cwd() الأصلية process.chdir(PATH_TO_NEXT_TRANSLATE) عندما يتعلق الأمر بمكونات الخادم ومكونات العميل ، فقد يكون من الصعب تحميل نفس الشيء على صفحات مختلفة. لتبسيط هذه العملية ، قمنا باستخراج كل التعقيد باستخدام next-translate-plugin .
إذا كنت مهتمًا بمعرفة المزيد حول كيفية عمل النقل التالي مع تطبيق Next.js 13 Dir Paradigm ، تحقق من هذه المقالة للحصول على شرح مفصل.
إذا كنت تستخدم مجلد "التطبيق" بدلاً من مجلد "الصفحات" ، فسوف يكتشف next-translate-plugin تلقائيًا التغيير ، ولن تحتاج إلى لمس أي من التكوين المترابط التالي. الفرق الوحيد هو أن خاصية تكوين "الصفحات" ستشير إلى الصفحات الموجودة داخل مجلد "التطبيق".
I18N.JS
module . exports = {
locales : [ 'en' , 'ca' , 'es' ] ,
defaultLocale : 'en' ,
pages : {
'*' : [ 'common' ] ,
'/' : [ 'home' ] , // app/page.tsx
'/second-page' : [ 'home' ] , // app/second-page/page.tsx
} ,
} ببساطة عن طريق تغيير مجلد "الصفحات" إلى "التطبيق" ، يمكنك استهلاك الترجمات داخل صفحاتك باستخدام خطاف useTranslation أو المكون Trans . ستظل ترى السجل (إذا تم تمكينه) لمعرفة مساحات الأسماء التي يتم تحميلها في كل صفحة ، ويجب أن يكون كل شيء آخر هو نفسه.
؟ صفحة الخادم/المكون (+0 كيلو بايت): app/page.js :
import useTranslation from 'next-translate/useTranslation'
export default function HomePage ( ) {
const { t , lang } = useTranslation ( 'home' )
return < h1 > { t ( 'title' ) } </ h1 >
} ؟ ️ صفحة العميل/المكون (+498 ب): app/checkout/page.js
"use client"
import useTranslation from 'next-translate/useTranslation'
export default function CheckoutPage ( ) {
const { t , lang } = useTranslation ( 'checkout' )
return < h1 > { t ( 'title' ) } </ h1 >
} قدمت Next.js 10 دعم التوجيه i18n ، مما يسمح بتقديم الصفحات عن طريق التنقل إلى /es/page-name ، حيث تم الوصول إلى pages/page-name.js باستخدام خطاف useRouter للحصول على locale .
ومع ذلك ، نظرًا لأن الصفحات قد تم نقلها من pages إلى تطبيق DIR ، فإن التوجيه I18N هذا لم يعد يعمل بشكل صحيح .
في النقل التالي ، اخترنا عدم إعادة تنفيذ هذه الوظيفة ، لأننا نهدف إلى أن نكون مكتبة لترجمة الصفحات ، بدلاً من توجيهها. نأمل أنه في المستقبل ، سيتم تنفيذ هذه الميزة في دليل app .
نوصي بما يلي:
[lang] إلى المستوى الأول. أي أن جميع صفحاتك ستكون في الداخل /app/[lang] .i18n.(js|json) لاحتواء /[lang] في البداية. module.exports = {
locales: ['en', 'ca', 'es'],
defaultLocale: 'en',
pages: {
'*': ['common'],
- '/': ['home'],
+ '/[lang]': ['home'],
- '/second-page': ['home'],
+ '/[lang]/second-page': ['home'],
},
} على مستوى المترجمة التالية ، نكتشف اللغة بالفعل تلقائيًا وفقًا لـ searchParams.get('lang') و params.lang . لذلك لا تحتاج إلى تكوينه لكل صفحة ، يمكنك استخدام next-translate كالمعتاد داخل صفحات/مكونات الخادم/العميل:
import useTranslation from 'next-translate/useTranslation'
import Trans from 'next-translate/Trans'
export default function Page ( ) {
const { t , lang } = useTranslation ( 'common' )
return (
< >
< h1 > { t `title` } </ h1 >
< Trans i18nKey = "common:another-text" components = { [ < b /> ] } />
</ >
)
} هناك عرض تجريبي next-translate على Next.js repo:
لاستخدامه:
npx create-next-app --example with-next-translate with-next-translate-app
# or
yarn create next-app --example with-next-translate with-next-translate-appهذا العرض التوضيحي في هذا المستودع:
git clone [email protected]:aralroca/next-translate.gitcd next-translateyarn && yarn example:basicعلى غرار العرض التجريبي الأساسي ولكن مع بعض الإضافات: TypeScript ، WebPack 5 ، MDX ، مع _app.js في الأعلى ، توجد صفحات موجودة في مجلد SRC/Pages ، وتحميل أماكن من SRC/الترجمات بهيكل مختلف.
هذا العرض التوضيحي في هذا المستودع:
git clone [email protected]:aralroca/next-translate.gitcd next-translateyarn && yarn example:complex على غرار العرض التجريبي المعقد ولكن مع بعض الإضافي: بدلاً من مجلد pages ، نستخدم مجلد تطبيق Next.js +13 مع نظام التخطيطات الجديد.
هذا العرض التوضيحي في هذا المستودع:
git clone [email protected]:aralroca/next-translate.gitcd next-translateyarn && yarn example:with-app-directoryعلى غرار المثال الأساسي ولكن تحميل مساحات أسماء الصفحة تقوم بإلغاء تنشيط محمل WebPack يدويًا في ملف Config I18N.JSON.
لا نوصي باستخدامه بهذه الطريقة. ومع ذلك ، فإننا نمنح الفرصة لأي شخص للقيام بذلك إذا لم يكن مرتاحًا لعملية WebPack Loader الخاصة بنا.
هذا العرض التوضيحي في هذا المستودع:
git clone [email protected]:aralroca/next-translate.gitcd next-translateyarn && yarn example:without-loader شكراً لهؤلاء الأشخاص الرائعين (مفتاح الرموز التعبيرية):
أرال روكا جوميز ؟ | فنسنت دوكوربز | Björn الهذيان | جاستن | بول ؟ | Ademílson F. Tonato | فول |
Bickmaev5 | بيير غريمود | رومان مينشين | egor | دارين | جيوفاني جيوردانو | يوجين |
أندرو تشونغ | ثانه مينه | كروتون | باتريك | Vantroy | جوي | Gurkerl83 |
Teemu Perämäki | لويس سيرانو | J-Schumann | أندريه هسو | Slevy85 | بيرند Artmüller | rihards ščeredins |
N4N5 | روبين مويا | توم إستيريز | دان نيدهام | برونو أنتونس | كان أتاكان | رومان |
أرنو جيمينيز | إدوين فيلدويزن | DUC NGO VIET | بيليل هيلالي | ويف | Michał Bar | ويف |
ماركس إنجل | Michał Bar | سحب | ماركس إنجل | فاسكو سيلفا | Vsevolod Volkov | فيليكس يان |
محمد الزقري | مارسيلو أوليفيرا | زاك سندرلاند | أندرو أفران | داني | Mateusz Lesiak | curetix |
هونزا ؟ | Hardikbandhiya | تيم أو. بيترز | لي مينغ | فرناندو غارسيا هيرنانديز | هيشيم فانتار | هوزيين أونال |
جيسي مارتن |
يتبع هذا المشروع مواصفات جميع المساهمين. مساهمات من أي نوع ترحيب!