Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c155b22
docs(concept): translated concepts files
RlxChap2 May 20, 2026
9b91f3d
feat(arabic): initialize Arabic translation
RlxChap2 May 19, 2026
5a012f2
docs(configuration): translate configuration pages
RlxChap2 May 19, 2026
0480688
docs(configuration): edited language terms
RlxChap2 May 19, 2026
d5d4938
docs(ar): add final newlines
RlxChap2 May 20, 2026
1255558
docs(ar): changing layout from ltr to rtl
RlxChap2 May 21, 2026
20243a2
feat(guides): guides arabic translation
arabpolice May 21, 2026
490920e
docs(guides): add contributors to getting started and index guides
RlxChap2 May 21, 2026
2834b21
docs(ar): fix MDX lint issues
RlxChap2 May 22, 2026
555817d
feat(i18n): add language switcher
RlxChap2 May 22, 2026
dbe712d
fix(ar): decode hash anchors
RlxChap2 May 22, 2026
0ad9876
test(e2e): update Arabic assertions
RlxChap2 May 22, 2026
0fe5f2a
fix(ar): encode heading anchors
RlxChap2 May 22, 2026
82f4e2d
docs(ar): fix links and lint
RlxChap2 May 22, 2026
0965c7c
docs(ar): fix config lint issues
RlxChap2 May 22, 2026
ba5abf7
docs(ar): format remaining config tables
RlxChap2 May 22, 2026
c24e449
docs(ar): fix asset guide lint
RlxChap2 May 22, 2026
5888eaa
docs(ar): fix guide lint issues
RlxChap2 May 22, 2026
decd952
fix(ar): lint site config module
RlxChap2 May 22, 2026
eeb1ab2
docs(contribute): translated contribute docs
semon009 May 24, 2026
9b379d6
docs: ar translation for plugins
MohaDev-69 May 25, 2026
0023618
feat: add plugin documentations
MohaDev-69 May 25, 2026
509a884
feat: add documentation for plugins
MohaDev-69 May 25, 2026
ff4753c
docs(api): translate api docs content
RlxChap2 Jun 9, 2026
4f0e1fc
docs(configuration): fixed translation in resolve.mdx
RlxChap2 Jun 9, 2026
021b7ea
docs(license): translate license to Arabic
RlxChap2 Jun 9, 2026
960b6bf
docs(webpack-awesome): translate awesome-webpack.mdx files to Arabic
RlxChap2 Jun 9, 2026
b929e84
docs(blog): fixed blog translate to Arabic
RlxChap2 Jun 9, 2026
0ecc8a1
docs(ar): translate plugins, contribute, loaders, guide, migrate and …
RlxChap2 Jun 9, 2026
5568891
fix(format): fixed format, conflicts and lint stages
RlxChap2 Jun 9, 2026
b628276
docs(ar): translating and fix main files to arabic
RlxChap2 Jun 9, 2026
8428ec0
fix(docs): preserve translated heading anchors
RlxChap2 Jun 9, 2026
2df9dcb
docs(ar): complete Arabic RTL localization
RlxChap2 Jun 14, 2026
c7610db
docs(cypress): fixed cypress e2e
RlxChap2 Jun 14, 2026
774cbea
docs(concept): fixed Arabic translation
0xMe2na Jun 17, 2026
dd66ae6
fix(docs): format Arabic configuration list
RlxChap2 Jun 18, 2026
ca75c88
fix(ar): preserve translated section anchors
RlxChap2 Aug 10, 2026
13521c6
style(ar): format rebased target documentation
RlxChap2 Aug 10, 2026
8096988
fix(ci): ignore generated manifest import
RlxChap2 Aug 10, 2026
cff5c09
fix(e2e): expect the translated migrate heading
RlxChap2 Aug 10, 2026
370a06a
fix(ar): preserve asset query suffix anchor
RlxChap2 Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"MD034": false,
"MD036": false,
"MD041": false,
"MD060": false,
"MD059": false,
"no-hard-tabs": false,
"whitespace": false
Expand Down
8 changes: 4 additions & 4 deletions cypress/e2e/check-server-side-rendering.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ describe("server side rendered page", () => {
cy.get('head meta[name="description"]').should(
"have.attr",
"content",
"Learn how to bundle a JavaScript application with webpack 5.",
"تعلّم كيفية تجميع تطبيق JavaScript باستخدام webpack 5.",
);
});

it("should find html tag with lang", () => {
cy.visit("/");
cy.get('html[lang="en"]');
cy.get('html[lang="ar"][dir="rtl"]');
});

it("should find meta charset", () => {
Expand All @@ -25,7 +25,7 @@ describe("server side rendered page", () => {
cy.get('head meta[name="description"]').should(
"have.attr",
"content",
"webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.",
"webpack هو module bundler. هدفه الأساسي حزم ملفات JavaScript لاستخدامها في المتصفح، ويمكنه كذلك تحويل أي resource أو asset تقريبًا وحزمه أو تجهيزه.",
);
});

Expand All @@ -34,6 +34,6 @@ describe("server side rendered page", () => {
cy.title().should("eq", "webpack");

cy.visit("/guides/getting-started/");
cy.title().should("eq", "Getting Started | webpack");
cy.title().should("eq", "البدء | webpack");
});
});
4 changes: 2 additions & 2 deletions cypress/e2e/mobile-and-404.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe("Mobile Sidebar", () => {
"sidebar-mobile--visible",
);

cy.get('button[aria-label="Toggle navigation menu"]').click();
cy.get('button[aria-label="فتح قائمة التنقل"]').click();
cy.get(".sidebar-mobile").should("have.class", "sidebar-mobile--visible");

cy.get(".sidebar-mobile__close").click();
Expand All @@ -23,7 +23,7 @@ describe("Mobile Sidebar", () => {
});

it("should close sidebar when clicking outside", () => {
cy.get('button[aria-label="Toggle navigation menu"]').click();
cy.get('button[aria-label="فتح قائمة التنقل"]').click();
// Click to the right of the 300px wide sidebar
cy.get("body").click(350, 500, { force: true });
cy.get(".sidebar-mobile").should(
Expand Down
7 changes: 3 additions & 4 deletions cypress/e2e/offline.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe("offline", () => {

it("shows /migrate/ page", () => {
const url = "/migrate/";
const text = "Migrate";
const text = "الترقية";

cy.visit(url);
cy.get("h1").contains(text);
Expand All @@ -73,9 +73,8 @@ describe("offline", () => {
cy.visit(url);
cy.get("h1").contains(text);

// click `guides` link
cy.get('a[title="guides"]').click();
cy.get("h1").contains("Guides");
cy.get('a[title="الأدلة"]').click();
cy.get("h1").contains("الأدلة");
});

it("open print dialog when accessing /printable url", () => {
Expand Down
10 changes: 7 additions & 3 deletions cypress/e2e/page-hash-navigation.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

describe("Page hash navigation", () => {
it("scrolls to the element specified by the hash", () => {
cy.visit("/guides/getting-started/#basic-setup");
const hash = encodeURI("#الإعداد-الأساسي");

cy.location("hash").should("eq", "#basic-setup");
cy.visit(`/guides/getting-started/${hash}`);

cy.get("#basic-setup", { timeout: 10000 })
cy.location("hash").then((locationHash) => {
expect(locationHash).to.equal(hash);
});

cy.get(`[id="${hash.slice(1)}"]`, { timeout: 10000 })
.should("exist")
.then(($el) => {
const rect = $el[0].getBoundingClientRect();
Expand Down
14 changes: 9 additions & 5 deletions cypress/e2e/scroll.cy.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"use strict";

const sizes = ["iphone-6", "macbook-15"];
const basicSetupHash = encodeURI("#الإعداد-الأساسي");
const compileInMemoryHash = encodeURI("#الترجمة-في-الذاكرة");
const developmentHash = encodeURI("#التطوير");
const generalHash = encodeURI("#عام");

describe("Scroll Test", () => {
for (const size of sizes) {
Expand All @@ -10,7 +14,7 @@ describe("Scroll Test", () => {
// scroll to Contributors section
cy.get('[data-testid="contributors"]').scrollIntoView();

cy.isNotInViewport("#basic-setup");
cy.isNotInViewport(`[id="${basicSetupHash.slice(1)}"]`);

cy.visit("/guides/build-performance/");
cy.isNotInViewport('[data-testid="contributors"]');
Expand All @@ -20,10 +24,10 @@ describe("Scroll Test", () => {
cy.visit("/guides/getting-started");
cy.get('[data-testid="contributors"]').scrollIntoView();

cy.visit("/guides/build-performance/#development");
// since we lazy load notification bar now, #development element is a little out of viewport now
cy.isInViewport("#compile-in-memory");
cy.isNotInViewport("#general");
cy.visit(`/guides/build-performance/${developmentHash}`);
// since we lazy load notification bar now, #التطوير element is a little out of viewport now
cy.isInViewport(`[id="${compileInMemoryHash.slice(1)}"]`);
cy.isNotInViewport(`[id="${generalHash.slice(1)}"]`);
});
}
});
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default defineConfig([
extends: [configs["browser/recommended-outdated-module"]],
files: [
"src/components/**/*.{js,jsx}",
"src/config/site.js",
"src/utilities/test-local-storage.js",
"src/*.jsx",
"src/sw.js",
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
"main": "n/a",
"scripts": {
"clean-dist": "rimraf ./dist",
"clean-printable": "rimraf \"src/content/**/printable.mdx\"",
"clean-printable": "rimraf --glob \"src/content/**/printable.mdx\"",
"preclean": "run-s clean-dist clean-printable",
"clean": "rimraf \"src/content/**/_*.mdx\" \"src/**/_*.json\" \"repositories/*.json\"",
"clean": "rimraf --glob \"src/content/**/_*.mdx\" \"src/**/_*.json\" \"repositories/*.json\"",
"start": "npm run clean-dist && webpack serve --config webpack.dev.mjs --env dev --progress --config-node-env development",
"content": "node src/scripts/build-content-tree.mjs ./src/content ./src/_content.json",
"bundle-analyze": "run-s clean fetch content && webpack --config webpack.prod.mjs --config-node-env production && run-s printable content && webpack --config webpack.ssg.mjs --config-node-env production --env ssg --profile --json > stats.json && webpack-bundle-analyzer stats.json",
Expand All @@ -43,15 +43,15 @@
"lint": "run-s lint:*",
"lint:prettier": "prettier --cache --list-different --ignore-unknown .",
"lint:js": "eslint --cache --cache-location .cache/.eslintcache .",
"lint:markdown": "markdownlint --config ./.markdownlint.json --rules ./src/utilities/markdown-lint-enforce-lang-aliases.js '**/*.{md,mdx}'",
"lint:markdown": "markdownlint --config ./.markdownlint.json --rules ./src/utilities/markdown-lint-enforce-lang-aliases.js \"**/*.{md,mdx}\"",
"lint:prose": "vale --config='.vale.ini' src/content",
"lint:links": "hyperlink -c 8 --root dist -r dist/index.html --canonicalroot https://webpack.js.org/ --internal --skip /plugins/extract-text-webpack-plugin/ --skip /printable --skip /contribute/Governance --skip https:// --skip http:// --skip sw.js --skip /vendor > internal-links.tap; cat internal-links.tap | tap-spot",
"sitemap": "cd dist && sitemap-static --ignore-file=../sitemap-ignore.json --pretty --prefix=https://webpack.js.org/ > sitemap.xml",
"rss": "node src/scripts/generate-rss.mjs",
"serve": "npm run build && sirv start ./dist --port 4000",
"preprintable": "npm run clean-printable",
"printable": "node ./src/scripts/concatenate-docs.mjs",
"jest": "NODE_OPTIONS=--experimental-vm-modules jest --config=jest.config.mjs",
"jest": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --config=jest.config.mjs",
"cypress:open": "cypress open",
"cypress:run": "cypress run --browser chrome",
"prettier": "prettier --cache --write --ignore-unknown .",
Expand Down
8 changes: 4 additions & 4 deletions src/components/CodeBlockWithCopy/CodeBlockWithCopy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ export default function CodeBlockWithCopy({ children }) {
? "bg-red-500 hover:bg-red-700"
: "bg-[#175d96] hover:bg-[#2f85d0]",
)}
aria-label="Copy code to clipboard"
aria-label="نسخ الكود إلى الحافظة"
>
{copyStatus === "copied"
? "Copied!"
? "تم النسخ"
: copyStatus === "error"
? "Error"
: "Copy"}
? "تعذر النسخ"
: "نسخ"}
</button>

<pre ref={preRef}>{children}</pre>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Dropdown/Dropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default function Dropdown({ className = "", items = [] }) {
ref={dropdownButtonRef}
aria-haspopup="true"
aria-expanded={String(active)}
aria-label="Select language"
aria-label="اختيار اللغة"
onClick={handleClick}
className="cursor-pointer text-white border-none bg-transparent m-0 p-0 text-[length:inherit] flex items-center"
>
Expand Down Expand Up @@ -141,7 +141,7 @@ export default function Dropdown({ className = "", items = [] }) {
href={item.url}
className="block min-w-[88px] px-3 py-1 text-center text-white transition-colors duration-[200ms] visited:text-white hover:bg-[#175d96] hover:text-white focus:bg-[#175d96] focus:text-white"
>
<span lang={item.lang} className="align-top text-left">
<span lang={item.lang} className="align-top text-start">
{item.title}
</span>
</a>
Expand Down
13 changes: 7 additions & 6 deletions src/components/Dropdown/Dropdown.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const items = [
{ title: "French", url: "/fr/", lang: "fr" },
{ title: "Spanish", url: "/es/", lang: "es" },
];
const languageButtonName = /اختيار اللغة/;

function getListWrapper(container) {
return container.querySelector("ul").closest("div");
Expand All @@ -24,7 +25,7 @@ describe("Dropdown", () => {
it("renders the toggle button", () => {
render(<Dropdown items={items} />);
expect(
screen.getByRole("button", { name: /select language/i }),
screen.getByRole("button", { name: languageButtonName }),
).toBeTruthy();
});

Expand Down Expand Up @@ -52,7 +53,7 @@ describe("Dropdown", () => {

it("toggles dropdown on button click", () => {
const { container } = render(<Dropdown items={items} />);
const button = screen.getByRole("button", { name: /select language/i });
const button = screen.getByRole("button", { name: languageButtonName });

fireEvent.click(button);
expect(getListWrapper(container).classList.contains("hidden")).toBe(false);
Expand All @@ -63,7 +64,7 @@ describe("Dropdown", () => {

it("sets aria-expanded correctly", () => {
render(<Dropdown items={items} />);
const button = screen.getByRole("button", { name: /select language/i });
const button = screen.getByRole("button", { name: languageButtonName });

expect(button.getAttribute("aria-expanded")).toBe("false");
fireEvent.click(button);
Expand All @@ -79,7 +80,7 @@ describe("Dropdown", () => {

it("closes on Escape key", () => {
const { container } = render(<Dropdown items={items} />);
const button = screen.getByRole("button", { name: /select language/i });
const button = screen.getByRole("button", { name: languageButtonName });

fireEvent.click(button);
expect(getListWrapper(container).classList.contains("hidden")).toBe(false);
Expand All @@ -95,7 +96,7 @@ describe("Dropdown", () => {

it("closes when clicking outside", () => {
const { container } = render(<Dropdown items={items} />);
const button = screen.getByRole("button", { name: /select language/i });
const button = screen.getByRole("button", { name: languageButtonName });

fireEvent.click(button);
expect(getListWrapper(container).classList.contains("hidden")).toBe(false);
Expand All @@ -109,7 +110,7 @@ describe("Dropdown", () => {

it("does not close dropdown when arrow keys are pressed", () => {
const { container } = render(<Dropdown items={items} />);
const button = screen.getByRole("button", { name: /select language/i });
const button = screen.getByRole("button", { name: languageButtonName });
fireEvent.click(button);

const links = screen.getAllByRole("link");
Expand Down
8 changes: 4 additions & 4 deletions src/components/Dropdown/__snapshots__/Dropdown.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ exports[`Dropdown matches snapshot 1`] = `
<button
aria-expanded="false"
aria-haspopup="true"
aria-label="Select language"
aria-label="اختيار اللغة"
class="cursor-pointer text-white border-none bg-transparent m-0 p-0 text-[length:inherit] flex items-center"
>
<svg
Expand Down Expand Up @@ -62,7 +62,7 @@ exports[`Dropdown matches snapshot 1`] = `
href="/en/"
>
<span
class="align-top text-left"
class="align-top text-start"
lang="en"
>
English
Expand All @@ -77,7 +77,7 @@ exports[`Dropdown matches snapshot 1`] = `
href="/fr/"
>
<span
class="align-top text-left"
class="align-top text-start"
lang="fr"
>
French
Expand All @@ -92,7 +92,7 @@ exports[`Dropdown matches snapshot 1`] = `
href="/es/"
>
<span
class="align-top text-left"
class="align-top text-start"
lang="es"
>
Spanish
Expand Down
Loading
Loading