18ways بلاگ
موجودہ Next.js ایپ میں SEO کو نقصان پہنچائے بغیر یا سب کچھ شروع سے دوبارہ بنائے بغیر ملٹی لنگول i18n اور لوکلائزیشن کیسے شامل کریں۔
I18n (internationalisation)، l10n (localisation)، multilingual support… آپ اسے کچھ بھی کہیں، آخرکار آپ کو اپنی Next.js app کو ایک سے زیادہ زبانوں کی حمایت کے لیے update کرنا ہی پڑتا ہے۔
مشکل ایک جملہ ترجمہ کرنے میں نہیں ہے۔ اصل چیلنج یہ ہے کہ ایک حقیقی Next.js ایپ میں SEO خراب کیے بغیر، اپنے کوڈبیس کو الجھائے بغیر، یا اپنے لیے خود ایک مینٹیننس مسئلہ کھڑا کیے بغیر متعدد زبانیں شامل کی جائیں۔
اگر آپ سیدھا کوڈ تک جانا چاہتے ہیں تو 18ways-next GitHub examples دیکھیں۔
سب سے پہلے، ہمیں اپنے پیکیجز انسٹال کرنے ہیں۔ ہم 18ways لائبز سیٹ اپ کریں گے، لیکن اگر آپ کا پروجیکٹ سادہ ہو اور اس میں صرف سٹَیٹک مواد ہو، تو i18next جیسے ٹولز بھی اچھی طرح کام کرتے ہیں۔
npm install @18ways/next @18ways/reactاپنی کنفیگ فائل بنائیں:
// 18ways.config.js
module.exports = {
apiKey: 'pk_dummy_demo_token',
baseLocale: 'en-GB',
router: 'app', // 'app', or 'path' depending on which Next.js router you are using
};اپنی Next.js کنفیگ کو ریپ کریں:
// next.config.js
const { withWays } = require('@18ways/next/config');
const nextConfig = {
/*
* your normal Next.js config here
*/
};
module.exports = withWays(nextConfig);ایک root proxy شامل کریں تاکہ / درست locale پر redirect ہو سکے:
// proxy.js
export { default, config } from '@18ways/next/proxy';پھر ایک localized layout شامل کریں:
// app/layout.jsx
import './styles.css';
import { WaysRoot } from '@18ways/next/server';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className="next-demo-body">
<WaysRoot>{children}</WaysRoot>
</body>
</html>
);
}اور بس، کام ختم! اب آپ کے پاس یہ ہیں:
اب آپ اپنا پہلا صفحہ ترجمہ کر سکتے ہیں۔ i18next جیسے tools کے لیے آپ کو اپنا سارا متن translation keys میں نکالنا پڑے گا، پھر انہیں اپنے code میں reference کرنا ہوگا۔ یہ بالکل کیسا نظر آئے گا، یہ اس library پر depend کرے گا جو آپ نے چنی ہے۔
اگر آپ 18ways استعمال کر رہے ہیں، تو آپ بس جس متن کا ترجمہ کرنا چاہتے ہیں اسے <T> component میں لپیٹ دیں:
// src/components/MyExampleComponent.jsx
import { useT, T } from '@18ways/react';
export default function MyExampleComponent() {
const t = useT();
return (
<div>
<T>Hello world!</T>
<img
src="https://example.com/image.png"
alt={t('Example image')}
/>
</div>
);
}ممکن ہے آپ صارفین کو اپنی زبان کی پسند بدلنے کی اجازت دینا چاہیں:
// src/components/Footer.jsx
import { T, LanguageSwitcher } from '@18ways/react';
export default function Footer() {
return (
<footer>
<T>My footer content</T>
<LanguageSwitcher />
</footer>
);
}جب بنیادی ڈھانچہ اپنی جگہ پر آ جائے، تو عموماً یہ پروجیکٹس چند طریقوں سے غلط ہو جاتے ہیں۔
سرور سائیڈ رینڈرنگ (SSR) وہ چیز ہے جو آپ کی Next.js ایپ کو پہلے سے رینڈر شدہ HTML سرور پر دینے کے قابل بناتی ہے۔ یہ SEO کے لیے بھی نہایت اہم ہے، اور اس لیے بھی کہ صارف کو خراب مواد یا غلط زبان کی جھلکیاں نظر نہ آئیں۔
اگر آپ i18next جیسی library استعمال کر رہے ہیں، تو آپ کو بہت احتیاط کرنی ہوگی کہ آپ کے ترجمے server-side render کے دوران load اور populate ہو رہے ہوں۔ آپ اس کی جانچ اپنی page کے view-source: کو دیکھ کر کر سکتے ہیں، مثلاً view-source:http://localhost:3000/۔ آپ کو یہ production میں بھی چیک کرنا چاہیے، تاکہ یقینی ہو جائے کہ یہ آپ کی production build میں بھی کام کرتا ہے۔
اگر آپ 18ways استعمال کر رہے ہیں، تو اس کی فکر نہ کریں۔ یہ سب آپ کے لیے سنبھال لیا جاتا ہے۔
اگر آپ 18ways استعمال کر رہے ہیں، تو آپ کو اس کے بارے میں بالکل فکر کرنے کی ضرورت نہیں۔ 18ways کو translation keys کی ضرورت نہیں ہوتی، آپ اپنا متن معمول کے مطابق اسی جگہ چھوڑ سکتے ہیں۔
بہت سے i18n سسٹمز آپ سے مطالبہ کرتے ہیں کہ آپ اپنے کوڈ کو ترجمے کی keys میں تقسیم کریں۔ ان keys کے نام رکھنے میں احتیاط کرنا اہم ہے۔
خراب کنجیاں مبہم ہوتی ہیں:
// bad-keys.en-GB.js
module.exports = {
title: 'Continue',
button: 'Pay now',
label: 'Home',
};وہ کنجیاں مترجمین اور ڈویلپرز کو تقریباً کچھ نہیں بتاتیں کہ متن کہاں ظاہر ہوتا ہے۔
بہتر کنجیوں میں سیاق و سباق شامل ہوتا ہے:
// better-keys.en-GB.js
module.exports = {
'checkout.payment.primaryButton': 'Pay now',
'checkout.payment.stepTitle': 'Complete your payment',
'account.sidebar.homeLink': 'Home',
};دینامک طور پر کنجیاں بنانے سے بھی بچیں:
// bad-dynamic-keys.js
const key = `checkout.${status}.${buttonType}`;
const translatedText = t(key);یہ ان IDE tools کو توڑ دے گا جو translation keys کو کم تکلیف دہ بنانے کی کوشش کرتی ہیں۔ اس سے پرانی translation keys کو تلاش کرنا اور صاف کرنا بھی انتہائی مشکل ہو جائے گا۔
// better-dynamic-keys.js
const keyMap = {
success: {
primary: t('checkout.success.primary'),
default: t('checkout.success.default'),
},
error: {
primary: t('checkout.error.primary'),
default: t('checkout.error.default'),
},
};
const translatedText = keyMap[status][buttonType];یہ DRY کے لحاظ سے کم ہے، لیکن ترجمے کی کنجیوں کو ناقابلِ انتظام بننے سے روکنے کا بہترین طریقہ ہے۔
اس سے بھی بہتر یہ ہے کہ 18ways جیسے tool کا استعمال کیا جائے، پھر آپ کو translation keys کی کبھی ضرورت ہی نہیں پڑتی:
// app/[lang]/checkout/page.jsx
<T>Pay now</T>لوکیل کی شناخت کا مطلب یہ طے کرنا ہے کہ صارف کو واضح طور پر زبان بدلنے سے پہلے کون سی زبان نظر آنی چاہیے۔
یہ عموماً ان میں سے کچھ کے امتزاج پر مشتمل ہوتا ہے:
Accept-Language ہیڈرسادہ Next.js middleware میں، یہ اکثر کچھ یوں نظر آتا ہے:
// middleware.js
/**
* You don't need any of this if you're using 18ways
*/
import { NextResponse } from 'next/server';
const acceptedLocales = ['en-GB', 'fr-FR'];
export function middleware(request) {
const savedLocale =
request.cookies.get('preferred-locale')?.value;
const browserLocale =
request.headers
.get('accept-language')
?.split(',')[0] || 'en-GB';
const locale = acceptedLocales.includes(savedLocale)
? savedLocale
: acceptedLocales.includes(browserLocale)
? browserLocale
: 'en-GB';
if (request.nextUrl.pathname === '/') {
return NextResponse.redirect(
new URL(`/${locale}`, request.url)
);
}
return NextResponse.next();
}کچھ لائبریریاں یہ کام آسان بنانے کے لیے helpers فراہم کرتی ہیں، مگر مختلف حد تک۔ 18ways کے ساتھ ابتدائی detection اور redirect layer آپ کے لیے سنبھالی جاتی ہے۔
مختلف لوکیلز تاریخوں، اعداد اور پیسے کو مختلف انداز میں فارمیٹ کرتے ہیں۔
مثال کے طور پر:
04/05/2026 کا مطلب 4 مئی بھی ہو سکتا ہے اور 5 اپریل بھی€1,999.00 اور 1.999,00 € دونوں درست ہیں، locale کے مطابقسادہ JavaScript میں، آپ یہ کام Intl کے ساتھ خود سنبھالتے ہیں:
// formatting-dates-and-currency.js
const myLocale = getCurrentLocale(); // depends on your lib
const someTimestamp = new Date('2026-04-13T09:00:00Z');
const dateLabel = new Intl.DateTimeFormat('fr-FR', {
dateStyle: 'long',
}).format(someTimestamp);
const someMoney = {
amount: 1999,
currency: 'EUR',
};
const moneyLabel = new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: someMoney.currency,
}).format(someMoney.amount);
const translatedText = t(
'my.translation.key',
{ dateLabel, moneyLabel }
);اگر آپ 18ways استعمال کر رہے ہیں، تو یہ آپ کے لیے سنبھال لیا جاتا ہے:
const someTimestamp = new Date('2026-04-13T09:00:00Z');
const someMoney = {
amount: 1999,
currency: 'EUR',
};
<T>My text with {{ someTimestamp }} and {{ someMoney }}</T>translated UI بنانے کے لیے ٹکڑوں کو جوڑ کر نہ بنائیں:
// bad-string-joining.jsx
const clickHereText = t('click.here');
const toGetStartedText = t('to.get.started')
<p><a href="#">{clickHereText}</a> {toGetStartedText}.</p>یہ کئی زبانوں میں ٹوٹ جائے گا۔
آپ انگریزی میں “👉👉Click here👈👈 to get started” کہہ سکتے ہیں، لیکن فرانسیسی میں یہ زیادہ فطری ہے کہ “Pour commencer, 👉👉cliquez ici👈👈”. کچھ زبانوں جیسے جاپانی میں تو پہلے اور بعد دونوں طرف الفاظ درکار ہوتے ہیں، جیسے “始めるには👉👉こちら👈👈をクリックしてください”.
جملے کی ساخت بدل سکتی ہے، اس لیے اسے حصّوں میں توڑ دینا ترجمے کو کہیں زیادہ مشکل بنا دیتا ہے۔
پورے جملے بہتر ترجمہ ہوتے ہیں، کیونکہ مترجم الفاظ کو قدرتی طور پر دوبارہ ترتیب دے سکتے ہیں اور معنی کو ایک مکمل اکائی کے طور پر دیکھ سکتے ہیں۔
اگر آپ اس طرح JSX کا ترجمہ کر رہے ہیں:
// rich-text-message.jsx
<p>
Something <strong>that we want to be bold</strong>
</p>اسے کیسے سنبھالنا ہے، اس کے لیے آپ کو اپنی i18n لائبریری سے رجوع کرنا ہوگا، کیونکہ مختلف لائبریریاں اسے بہت مختلف طریقے سے ہینڈل کرتی ہیں۔
اگر آپ 18ways استعمال کر رہے ہیں، تو آپ آسانی سے پورا JSX بلاک بالکل عام طریقے سے ترجمہ کر سکتے ہیں۔
// rich-text-message.jsx
<p>
<T>Something <strong>that we want to be bold</strong></T>
</p>ویری ایبلز آپ کو جملے کو مکمل رکھنے دیتے ہیں، جبکہ runtime values بھی داخل کی جا سکتی ہیں۔
زیادہ تر i18n لائبریریاں یہ کسی نہ کسی شکل میں سپورٹ کرتی ہیں۔ 18ways کے ساتھ:
// app/[lang]/page.jsx
<T>Hello {{ name: 'Ada' }}</T>یہ پیٹرن ان کے لیے اچھی طرح کام کرتا ہے:
جملہ پڑھنے کے قابل رہتا ہے، اور value واضح رہتی ہے۔
اگر آپ چاہتے ہیں کہ خود ویری ایبل کا بھی ترجمہ ہو، تو اسے t(...) میں لپیٹنا یقینی بنائیں:
const animal = t('dog');
<T>Favourite animal: {{ animal }}</T>Plural کے قواعد زبان کے حساب سے مختلف ہوتے ہیں۔ انگریزی میں plural کی ایک شکل ہے (1 year، 2 years، وغیرہ)۔ پولش میں plural کی کئی شکلیں ہیں (1 rok، 2 lata، 5 lat)۔ جاپانی میں plural کی کوئی شکل ہی نہیں ہوتی (1 年، 2 年، 3 年)۔
زیادہ تر i18n لائبریریاں plurals سنبھالنے کے لیے ICU جیسی syntax specify کرنے دیتی ہیں:
// app/[lang]/page.jsx
<T>
{{
unreadCount,
format:
'plural, =0{No unread messages} =1{One unread message} other{{unreadCount} unread messages}',
}}
</T>اوپر والا 18ways میں کام کرے گا، لیکن زیادہ تر صورتوں میں آپ یہ بھی کر سکتے ہیں:
// app/[lang]/page.jsx
<T>{{ unreadCount }} unread messages</T>18ways آپ کے لیے plurals سنبھال لے گا!
Next.js app میں متعدد زبانیں شامل کرنا کسی rewrite project میں بدلنے کی ضرورت نہیں۔
اگر آپ 18ways جیسا حل استعمال نہیں کر رہے — تو یقینی بنائیں کہ آپ کی routing اور SSR درست ہوں، پھر اپنی copy کو translation keys میں منتقل کریں، اور عام i18n مشکلات سے بچیں۔
اگر آپ 18ways استعمال کر رہے ہیں، تو یہ سب کچھ آپ کے لیے سنبھالا جاتا ہے، اور آپ کو بس اپنے متن کو <T> blocks میں لپیٹنا شروع کرنا ہے!