diff --git a/guide/id/concept/configuration.md b/guide/id/concept/configuration.md
new file mode 100644
index 00000000..1420996c
--- /dev/null
+++ b/guide/id/concept/configuration.md
@@ -0,0 +1,344 @@
+# Konfigurasi
+
+Ada banyak cara untuk mengonfigurasi aplikasi Anda. Kita akan fokus pada konsep yang digunakan dalam
+[template proyek default](https://github.com/yiisoft/app).
+
+Konfigurasi Yii3 adalah bagian dari aplikasi. Anda dapat mengubah banyak aspek cara kerja aplikasi dengan mengedit
+konfigurasi di dalam `config/`.
+
+## Plugin konfigurasi
+
+Dalam template aplikasi digunakan [yiisoft/config](https://github.com/yiisoft/config). Karena menulis seluruh konfigurasi
+aplikasi dari awal adalah proses yang melelahkan, banyak paket menawarkan konfigurasi default, dan plugin membantu
+menyalin konfigurasi-konfigurasi tersebut ke dalam aplikasi.
+
+Untuk menawarkan konfigurasi default, `composer.json` dari paket harus memiliki bagian `config-plugin`.
+Saat memasang atau memperbarui paket dengan Composer, plugin membaca bagian `config-plugin` untuk setiap dependensi,
+menyalin berkas-berkas tersebut ke `config/packages/` aplikasi jika belum ada dan menulis rencana penggabungan ke
+`config/packages/merge_plan.php`. Rencana penggabungan mendefinisikan bagaimana menggabungkan konfigurasi-konfigurasi menjadi
+satu array besar yang siap diteruskan ke [DI container](di-container.md).
+
+Lihat apa yang ada di `composer.json` "yiisoft/app" secara default:
+
+```json
+"config-plugin-options": {
+ "output-directory": "config/packages"
+},
+"config-plugin": {
+ "common": "config/common/*.php",
+ "params": [
+ "config/params.php",
+ "?config/params-local.php"
+ ],
+ "web": [
+ "$common",
+ "config/web/*.php"
+ ],
+ "console": [
+ "$common",
+ "config/console/*.php"
+ ],
+ "events": "config/events.php",
+ "events-web": [
+ "$events",
+ "config/events-web.php"
+ ],
+ "events-console": [
+ "$events",
+ "config/events-console.php"
+ ],
+ "providers": "config/providers.php",
+ "providers-web": [
+ "$providers",
+ "config/providers-web.php"
+ ],
+ "providers-console": [
+ "$providers",
+ "config/providers-console.php"
+ ],
+ "routes": "config/routes.php"
+},
+```
+
+Terdapat banyak konfigurasi bernama. Untuk setiap nama ada sebuah konfigurasi.
+
+String berarti plugin mengambil konfigurasi apa adanya dan menggabungkannya dengan konfigurasi bernama sama dari paket yang Anda butuhkan.
+Hal ini terjadi jika paket-paket tersebut memiliki `config-plugin` di `composer.json` mereka.
+
+Array berarti plugin akan menggabungkan banyak berkas sesuai urutan yang ditentukan.
+
+`?` di awal jalur berkas menunjukkan bahwa berkas tersebut mungkin tidak ada. Dalam kasus ini, berkas dilewati.
+
+`$` di awal nama berarti referensi ke konfigurasi bernama lain.
+
+`params` agak istimewa karena dicadangkan untuk parameter aplikasi. Ini otomatis tersedia sebagai `$params` di semua berkas konfigurasi lainnya.
+
+Anda dapat mempelajari lebih lanjut tentang fitur plugin konfigurasi [dari dokumentasinya](https://github.com/yiisoft/config/blob/master/README.md).
+
+## Berkas konfigurasi
+
+Sekarang, setelah Anda tahu bagaimana plugin merakit konfigurasi, lihat direktori `config`:
+
+```
+common/
+ application-parameters.php
+ i18n.php
+ router.php
+console/
+packages/
+ yiisoft/
+ dist.lock
+ merge_plan.php
+web/
+ application.php
+ psr17.php
+events.php
+events-console.php
+events-web.php
+params.php
+providers.php
+providers-console.php
+providers-web.php
+routes.php
+```
+
+### Konfigurasi container
+
+Aplikasi terdiri dari sekumpulan layanan yang terdaftar di dalam [dependency container](di-container.md). Berkas-berkas konfigurasi
+yang bertanggung jawab untuk konfigurasi langsung dependency container berada di bawah direktori `common/`, `console/` dan `web/`.
+Kita menggunakan `web/` untuk konfigurasi spesifik aplikasi web dan `console/` untuk konfigurasi spesifik perintah konsol. Baik web maupun
+console berbagi konfigurasi di bawah `common/`.
+
+```php
+ [
+ 'class' => ApplicationParameters::class,
+ 'charset()' => [$params['app']['charset']],
+ 'name()' => [$params['app']['name']],
+ ],
+];
+```
+
+Plugin konfigurasi meneruskan variabel khusus `$params` ke semua berkas konfigurasi.
+Kode di atas meneruskan nilainya ke layanan.
+
+Panduan ["Dependency injection and container"](di-container.md) menjelaskan
+format konfigurasi dan gagasan dependency injection secara rinci.
+
+Untuk kenyamanan, ada konvensi penamaan untuk kunci string kustom:
+
+1. Awali dengan nama paket seperti `yiisoft/cache-file/custom-definition`.
+2. Jika konfigurasi untuk aplikasi itu sendiri, lewati prefix paket, misalnya `custom-definition`.
+
+### Service provider
+
+Sebagai alternatif mendaftarkan dependensi secara langsung, Anda dapat menggunakan service provider. Pada dasarnya, ini adalah kelas-kelas yang
+mengonfigurasi dan mendaftarkan layanan di dalam container berdasarkan parameter yang diberikan. Mirip dengan tiga berkas konfigurasi
+dependensi yang dijelaskan sebelumnya, ada tiga konfigurasi untuk menentukan service provider: `providers-console.php` untuk perintah konsol,
+`providers-web.php` untuk aplikasi web dan `providers.php` untuk keduanya:
+
+```php
+/* @var array $params */
+
+// ...
+use App\Provider\CacheProvider;
+use App\Provider\MiddlewareProvider;
+// ...
+
+return [
+ // ...
+ 'yiisoft/yii-web/middleware' => MiddlewareProvider::class,
+ 'yiisoft/cache/cache' => [
+ 'class' => CacheProvider::class,
+ '__construct()' => [
+ $params['yiisoft/cache-file']['file-cache']['path'],
+ ],
+ ],
+ // ...
+```
+
+Dalam konfigurasi ini kunci adalah nama provider. Menurut konvensi, ini berupa `vendor/package-name/provider-name`. Nilai adalah nama kelas provider.
+Kelas-kelas ini bisa dibuat dalam proyek itu sendiri atau disediakan oleh paket.
+
+Jika Anda perlu mengonfigurasi beberapa opsi untuk sebuah layanan, mirip dengan konfigurasi container langsung, ambil nilai
+dari `$params` dan teruskan ke provider.
+
+Provider harus mengimplementasikan satu metode, `public function register(Container $container): void`. Dalam metode ini Anda
+perlu menambahkan layanan ke container menggunakan metode `set()`. Di bawah ini adalah contoh provider untuk layanan cache:
+
+```php
+use Psr\Container\ContainerInterface;
+use Psr\SimpleCache\CacheInterface;
+use Yiisoft\Aliases\Aliases;
+use Yiisoft\Cache\Cache;
+use Yiisoft\Cache\CacheInterface as YiiCacheInterface;
+use Yiisoft\Cache\File\FileCache;
+use Yiisoft\Di\Container;
+use Yiisoft\Di\Support\ServiceProvider;
+
+final readonly class CacheProvider extends ServiceProvider
+{
+ public function __construct(
+ private string $cachePath = '@runtime/cache'
+ )
+ {
+ $this->cachePath = $cachePath;
+ }
+
+ public function register(Container $container): void
+ {
+ $container->set(CacheInterface::class, function (ContainerInterface $container) {
+ $aliases = $container->get(Aliases::class);
+
+ return new FileCache($aliases->get($this->cachePath));
+ });
+
+ $container->set(YiiCacheInterface::class, Cache::class);
+ }
+}
+```
+
+### Routes
+
+Anda dapat mengonfigurasi bagaimana aplikasi web merespons URL tertentu di `config/routes.php`:
+
+```php
+use App\Controller\SiteController;
+use Yiisoft\Router\Route;
+
+return [
+ Route::get('/')->action([SiteController::class, 'index'])->name('site/index')
+];
+```
+
+Baca lebih lanjut tentang ini di ["Routes"](../runtime/routing.md).
+
+### Events
+
+Banyak layanan memancarkan event tertentu yang bisa Anda lampirkan (attach).
+Anda dapat melakukannya melalui tiga berkas konfigurasi: `events-web.php` untuk event aplikasi web,
+`events-console.php` untuk event konsol dan `events.php` untuk keduanya.
+Konfigurasinya adalah sebuah array di mana kunci adalah nama event dan nilainya adalah array handler:
+
+```php
+return [
+ EventName::class => [
+ // Just a regular closure, it will be called from the Dispatcher "as is".
+ static fn (EventName $event) => someStuff($event),
+
+ // A regular closure with an extra dependency. All the parameters after the first one (the event itself)
+ // will be resolved from your DI container within `yiisoft/injector`.
+ static fn (EventName $event, DependencyClass $dependency) => someStuff($event),
+
+ // An example with a regular callable. If the `staticMethodName` method has some dependencies,
+ // they will be resolved the same way as in the earlier example.
+ [SomeClass::class, 'staticMethodName'],
+
+ // Non-static methods are allowed too. In this case, `SomeClass` will be instantiated by your DI container.
+ [SomeClass::class, 'methodName'],
+
+ // An object of a class with the `__invoke` method implemented
+ new InvokableClass(),
+
+ // In this case, the `InvokableClass` with the `__invoke` method will be instantiated by your DI container
+ InvokableClass::class,
+
+ // Any definition of an invokable class may be here while your `$container->has('the definition)`
+ 'di-alias'
+ ],
+];
+```
+
+Read more about it in ["Events"](events.md).
+
+
+Baca lebih lanjut mengenai ini di ["Events"](events.md).
+
+### Parameter
+
+Parameter pada `config/params.php` menyimpan nilai konfigurasi yang digunakan di berkas konfigurasi lain untuk mengonfigurasi layanan
+dan service provider.
+
+> [!TIP]
+> Jangan menggunakan parameter, konstanta, atau variabel environment secara langsung di aplikasi Anda; konfigurasikan
+> layanan sebagai gantinya.
+
+Params `params.php` aplikasi default terlihat seperti berikut:
+
+```php
+ [
+ 'charset' => 'UTF-8',
+ 'locale' => 'en',
+ 'name' => 'My Project',
+ ],
+
+ 'yiisoft/aliases' => [
+ 'aliases' => [
+ '@root' => dirname(__DIR__),
+ '@assets' => '@root/public/assets',
+ '@assetsUrl' => '/assets',
+ '@baseUrl' => '/',
+ '@message' => '@root/resources/message',
+ '@npm' => '@root/node_modules',
+ '@public' => '@root/public',
+ '@resources' => '@root/resources',
+ '@runtime' => '@root/runtime',
+ '@vendor' => '@root/vendor',
+ '@layout' => '@resources/views/layout',
+ '@views' => '@resources/views',
+ ],
+ ],
+
+ 'yiisoft/yii-view' => [
+ 'injections' => [
+ Reference::to(ContentViewInjection::class),
+ Reference::to(CsrfViewInjection::class),
+ Reference::to(LayoutViewInjection::class),
+ ],
+ ],
+
+ 'yiisoft/yii-console' => [
+ 'commands' => [
+ 'hello' => Hello::class,
+ ],
+ ],
+];
+```
+
+Untuk kenyamanan, terdapat konvensi penamaan mengenai parameter:
+
+1. Kelompokkan parameter berdasarkan nama paket seperti `yiisoft/cache-file`.
+2. Jika parameter untuk aplikasi itu sendiri, seperti `app`, lewati prefix paket.
+3. Jika terdapat banyak layanan dalam paket, seperti `file-target` dan `file-rotator` di paket `yiisoft/log-target-file`,
+ kelompokkan parameter berdasarkan nama layanan.
+4. Gunakan `enabled` sebagai nama parameter agar dapat menonaktifkan atau mengaktifkan sebuah layanan, misalnya `yiisoft/yii-debug`.
+
+### Konfigurasi paket
+
+Plugin konfigurasi yang dijelaskan menyalin konfigurasi paket default ke direktori `packages/`. Setelah disalin Anda
+menjadi pemilik konfigurasi tersebut, sehingga Anda dapat menyesuaikannya sesuka hati. `yiisoft/` dalam template default menunjukkan vendor paket. Karena
+hanya paket `yiisoft` yang ada di template, terdapat satu direktori. `merge_plan.php` digunakan saat runtime untuk mendapatkan urutan
+bagaimana konfigurasi-konfigurasi digabungkan.
+Perlu dicatat bahwa untuk kunci konfigurasi seharusnya ada satu sumber kebenaran (single source of truth).
+Satu konfigurasi tidak bisa menimpa nilai dari konfigurasi lain.
+
+`dist.lock` digunakan oleh plugin untuk melacak perubahan dan menampilkan diff antara konfigurasi saat ini dan contoh.
diff --git a/guide/id/concept/di-container.md b/guide/id/concept/di-container.md
new file mode 100644
index 00000000..5388cf2b
--- /dev/null
+++ b/guide/id/concept/di-container.md
@@ -0,0 +1,211 @@
+# Dependency injection dan container
+
+## Dependency injection
+
+Ada dua cara untuk menggunakan kembali (re-use) sesuatu dalam OOP: pewarisan (inheritance) dan komposisi (composition).
+
+Pewarisan itu sederhana:
+
+```php
+class Cache
+{
+ public function getCachedValue($key)
+ {
+ // ..
+ }
+}
+
+final readonly class CachedWidget extends Cache
+{
+ public function render(): string
+ {
+ $output = $this->getCachedValue('cachedWidget');
+ if ($output !== null) {
+ return $output;
+ }
+ // ...
+ }
+}
+```
+
+Masalahnya, kedua kelas ini menjadi saling terkait secara berlebihan (coupled) atau saling bergantung sehingga menjadi lebih rapuh.
+
+Cara lain untuk menangani ini adalah komposisi:
+
+
+```php
+interface CacheInterface
+{
+ public function getCachedValue($key);
+}
+
+final readonly class Cache implements CacheInterface
+{
+ public function getCachedValue($key)
+ {
+ // ..
+ }
+}
+
+final readonly class CachedWidget
+{
+ public function __construct(
+ private CacheInterface $cache
+ )
+ {
+ }
+
+ public function render(): string
+ {
+ $output = $this->cache->getCachedValue('cachedWidget');
+ if ($output !== null) {
+ return $output;
+ }
+ // ...
+ }
+}
+```
+
+Kita menghindari pewarisan yang tidak perlu dan menggunakan interface untuk mengurangi keterikatan (coupling). Anda dapat mengganti implementasi cache tanpa mengubah `CachedWidget`, sehingga komponennya menjadi lebih stabil.
+
+`CacheInterface` di sini adalah sebuah dependency: sebuah objek yang menjadi ketergantungan objek lain.
+Proses memasukkan instance dependency ke dalam objek (`CachedWidget`) disebut dependency injection.
+Ada banyak cara untuk melakukannya:
+
+- Injeksi konstruktor (Constructor injection). Terbaik untuk dependency yang wajib.
+- Injeksi metode (Method injection). Terbaik untuk dependency yang opsional.
+- Injeksi properti (Property injection). Sebaiknya dihindari di PHP kecuali mungkin untuk data transfer object.
+
+
+## DI container
+
+Menginjeksikan dependency dasar itu sederhana dan mudah. Anda memilih tempat di mana Anda tidak peduli tentang dependency,
+biasanya sebuah action handler (penangan aksi), yang biasanya tidak akan Anda unit-test, membuat instance dependency yang dibutuhkan
+dan meneruskannya ke kelas-kelas yang bergantung.
+
+Cara ini bekerja baik saat jumlah dependency sedikit dan tidak ada dependency bersarang. Ketika jumlahnya banyak dan setiap dependency
+memiliki dependency sendiri, membuat keseluruhan hirarki menjadi proses yang melelahkan, membutuhkan banyak kode, dan dapat menyebabkan
+kesalahan yang sulit dideteksi.
+
+Selain itu, banyak dependency, seperti pembungkus (wrapper) API pihak ketiga tertentu, sama untuk setiap kelas yang menggunakannya.
+Jadi masuk akal untuk:
+
+- Menentukan cara membuat instance pembungkus API tersebut sekali saja.
+- Membuatnya saat diperlukan dan hanya sekali per permintaan.
+
+Itulah fungsi dependency container.
+
+Dependency injection (DI) container adalah sebuah objek yang tahu bagaimana membuat dan mengonfigurasi objek serta
+semua objek dependensinya. [Artikel Martin Fowler](https://martinfowler.com/articles/injection.html) menjelaskan dengan baik
+mengapa DI container berguna. Di sini kita akan menjelaskan penggunaan DI container yang disediakan oleh Yii.
+
+Yii menyediakan fitur DI container melalui paket [yiisoft/di](https://github.com/yiisoft/di) dan
+paket [yiisoft/injector](https://github.com/yiisoft/injector).
+
+### Mengonfigurasi container
+
+Karena untuk membuat objek baru Anda membutuhkan dependency-nya, Anda harus mendaftarkannya sedini mungkin.
+Anda dapat melakukannya di konfigurasi aplikasi, mis. `config/web.php`. Untuk layanan berikut:
+
+```php
+final class MyService implements MyServiceInterface
+{
+ public function __construct(int $amount)
+ {
+ }
+
+ public function setDiscount(int $discount): void
+ {
+
+ }
+}
+```
+
+konfigurasinya bisa seperti:
+
+```php
+return [
+ MyServiceInterface::class => [
+ 'class' => MyService::class,
+ '__construct()' => [42],
+ 'setDiscount()' => [10],
+ ],
+];
+```
+
+Itu setara dengan:
+
+```php
+$myService = new MyService(42);
+$myService->setDiscount(10);
+```
+
+Ada metode tambahan untuk mendeklarasikan dependency:
+
+```php
+return [
+ // declare a class for an interface, resolve dependencies automatically
+ EngineInterface::class => EngineMarkOne::class,
+
+ // array definition (same as above)
+ 'full_definition' => [
+ 'class' => EngineMarkOne::class,
+ '__construct()' => [42],
+ '$propertyName' => 'value',
+ 'setX()' => [42],
+ ],
+
+ // closure
+ 'closure' => static function(ContainerInterface $container) {
+ return new MyClass($container->get('db'));
+ },
+
+ // static call
+ 'static_call' => [MyFactory::class, 'create'],
+
+ // instance of an object
+ 'object' => new MyClass(),
+];
+```
+
+### Menginjeksikan dependency
+
+Mereferensikan container secara langsung dalam sebuah kelas adalah ide yang buruk karena kode menjadi tidak generik, terikat pada antarmuka container
+dan, yang lebih buruk, dependency menjadi tersembunyi. Karena itu, Yii membalik kontrol dengan secara otomatis menginjeksikan
+objek dari container ke beberapa konstruktor dan metode berdasarkan tipe argumen metode.
+
+Ini terutama dilakukan pada konstruktor dan metode penangan aksi:
+
+```php
+use \Yiisoft\Cache\CacheInterface;
+
+final readonly class MyController
+{
+ public function __construct(
+ private CacheInterface $cache
+ )
+ {
+ $this->cache = $cache;
+ }
+
+ public function actionDashboard(RevenueReport $report)
+ {
+ $reportData = $this->cache->getOrSet('revenue_report', function() use ($report) {
+ return $report->getData();
+ });
+
+ return $this->render('dashboard', [
+ 'reportData' => $reportData,
+ ]);
+ }
+}
+```
+
+Karena [yiisoft/injector](https://github.com/yiisoft/injector) yang membuat dan memanggil action handler, ia
+memeriksa tipe argumen konstruktor dan metode, mengambil dependency dengan tipe tersebut dari container dan meneruskannya sebagai argumen. Hal ini biasanya disebut auto-wiring. Ini juga berlaku untuk sub-dependency: jika Anda tidak memberikan dependency secara eksplisit, container akan memeriksa apakah ia memiliki dependency tersebut terlebih dahulu.
+Cukup deklarasikan dependency yang Anda butuhkan, dan dependency itu akan diambil dari container secara otomatis.
+
+
+## Referensi
+
+- [Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler](https://martinfowler.com/articles/injection.html)
diff --git a/guide/id/concept/events.md b/guide/id/concept/events.md
new file mode 100644
index 00000000..36b4371b
--- /dev/null
+++ b/guide/id/concept/events.md
@@ -0,0 +1,142 @@
+# Events
+
+Events memungkinkan Anda menjalankan kode kustom pada titik-titik eksekusi tertentu tanpa memodifikasi kode yang sudah ada.
+Anda dapat melampirkan kode kustom yang disebut "handler" ke sebuah event sehingga ketika event tersebut dipicu, handler
+akan dijalankan secara otomatis.
+
+Contohnya, ketika seorang pengguna mendaftar, Anda perlu mengirim email sambutan. Anda bisa melakukannya langsung di
+`SignupService` tetapi kemudian, ketika Anda juga perlu mengubah ukuran (resize) gambar avatar pengguna, Anda harus
+mengubah kode `SignupService` lagi. Dengan kata lain, `SignupService` akan terikat (coupled) pada kode pengirim email dan
+kode pengubah ukuran avatar.
+
+Untuk menghindari hal itu, alih-alih menentukan apa yang harus dilakukan setelah pendaftaran secara eksplisit, Anda dapat
+mengangkat (raise) event `UserSignedUp` lalu menyelesaikan proses pendaftaran. Kode pengirim email dan kode pengubah ukuran
+avatar akan melampirkan handler ke event tersebut dan, oleh karena itu, akan dijalankan. Jika sewaktu-waktu Anda perlu melakukan
+tindakan tambahan saat pendaftaran, Anda bisa menambahkan handler event tanpa memodifikasi `SignupService`.
+
+Untuk menaikkan event dan melampirkan handler ke event-event tersebut, Yii menyediakan layanan khusus bernama event dispatcher.
+Layanan ini tersedia dari paket [yiisoft/event-dispatcher](https://github.com/yiisoft/event-dispatcher).
+
+## Event Handlers
+
+Event handler adalah sebuah [PHP callable](https://www.php.net/manual/en/language.types.callable.php) yang dijalankan
+ketika event yang dilampirkannya dipicu.
+
+Tanda tangan (signature) dari sebuah event handler adalah:
+
+```php
+function (EventClass $event) {
+ // handle it
+}
+```
+
+## Melampirkan event handlers
+
+Anda dapat melampirkan handler ke sebuah event seperti berikut:
+
+```php
+use Yiisoft\EventDispatcher\Provider\Provider;
+
+final readonly class WelcomeEmailSender
+{
+ public function __construct(Provider $provider)
+ {
+ $provider->attach([$this, 'handleUserSignup']);
+ }
+
+ public function handleUserSignup(UserSignedUp $event)
+ {
+ // handle it
+ }
+}
+```
+
+Metode `attach()` menerima sebuah callback. Berdasarkan tipe argumen callback tersebut, jenis event akan ditentukan.
+
+## Urutan event handlers
+
+Anda dapat melampirkan satu atau lebih handler ke sebuah event. Ketika sebuah event dipicu, handler yang terlampir
+akan dipanggil sesuai urutan saat mereka dilampirkan pada event. Jika sebuah event mengimplementasikan
+`Psr\EventDispatcher\StoppableEventInterface`, handler event dapat menghentikan eksekusi handler-handler berikutnya
+jika `isPropagationStopped()` mengembalikan `true`.
+
+Secara umum, lebih baik tidak bergantung pada urutan eksekusi handler event.
+
+## Menaikkan event
+
+Event dinaikkan (dispatched) seperti berikut:
+
+```php
+use Psr\EventDispatcher\EventDispatcherInterface;
+
+final readonly class SignupService
+{
+ public function __construct(
+ private EventDispatcherInterface $eventDispatcher
+ )
+ {
+ }
+
+ public function signup(SignupForm $form)
+ {
+ // handle signup
+
+ $event = new UserSignedUp($form);
+ $this->eventDispatcher->dispatch($event);
+ }
+}
+```
+
+Pertama, Anda membuat sebuah event dengan menyertakan data yang mungkin berguna bagi handler. Lalu Anda mendispatch event itu.
+
+Kelas event itu sendiri dapat terlihat seperti berikut:
+
+```php
+final readonly class UserSignedUp
+{
+ public function __construct(
+ public SignupForm $form
+ )
+ {
+ }
+}
+```
+
+## Hirarki Events
+
+Events tidak memiliki nama atau pencocokan wildcard atas tujuan tertentu. Nama kelas event dan hirarki kelas/interface
+serta komposisi dapat digunakan untuk mencapai fleksibilitas yang baik:
+
+```php
+interface DocumentEvent
+{
+}
+
+final readonly class BeforeDocumentProcessed implements DocumentEvent
+{
+}
+
+final readonly class AfterDocumentProcessed implements DocumentEvent
+{
+}
+```
+
+Dengan menggunakan interface, Anda dapat mendengarkan semua event yang berkaitan dengan dokumen:
+
+```php
+$provider->attach(function (DocumentEvent $event) {
+ // log events here
+});
+```
+
+## Melepas (detaching) event handlers
+
+Untuk melepas handler dari sebuah event Anda dapat memanggil metode `detach()`:
+
+```php
+$provider->detach(DocmentEvent::class);
+```
+
+## Mengonfigurasi event aplikasi
+
+Biasanya Anda menugaskan (assign) event handler melalui konfigurasi aplikasi. Lihat ["Configuration"](configuration.md) untuk detail.
diff --git a/guide/id/concept/immutability.md b/guide/id/concept/immutability.md
new file mode 100644
index 00000000..5d7cff80
--- /dev/null
+++ b/guide/id/concept/immutability.md
@@ -0,0 +1,149 @@
+# Immutability
+
+Immutability berarti status (state) sebuah objek tidak dapat diubah setelah objek tersebut dibuat.
+Alih-alih memodifikasi sebuah instance, Anda membuat instance baru dengan perubahan yang diinginkan.
+Pendekatan ini umum untuk objek bernilai (value objects) seperti Money, ID, dan DTO. Ini membantu menghindari efek samping yang tidak disengaja:
+metode tidak dapat diam-diam mengubah state yang dibagi, sehingga kode menjadi lebih mudah untuk dipahami.
+
+## Perangkap mutable (yang kita hindari)
+
+```php
+// A shared base query built once and reused:
+$base = Post::find()->where(['status' => Post::STATUS_PUBLISHED]);
+
+// Somewhere deep in the code we only need one post:
+$one = $base->limit(1)->one(); // mutates the underlying builder (sticky limit!)
+
+// Later we reuse the same $base expecting a full list:
+$list = $base->orderBy(['created_at' => SORT_DESC])->all();
+// Oops: still limited to 1 because the previous limit(1) modified $base.
+```
+
+## Membuat objek immutable di PHP
+
+Tidak ada cara langsung untuk memodifikasi sebuah instance, tetapi Anda dapat menggunakan clone untuk membuat instance baru dengan perubahan yang diinginkan.
+Itulah yang dilakukan metode `with*`.
+
+```php
+final class Money
+{
+ public function __construct(
+ private int $amount,
+ private string $currency,
+ ) {
+ $this->validateAmount($amount);
+ $this->validateCurrency($currency);
+ }
+
+ private function validateAmount(string $amount)
+ {
+ if ($amount < 0) {
+ throw new InvalidArgumentException('Amount must be positive.');
+ }
+ }
+
+ private function validateCurrency(string $currency)
+ {
+ if (!in_array($currency, ['USD', 'EUR'])) {
+ throw new InvalidArgumentException('Invalid currency. Only USD and EUR are supported.');
+ }
+ }
+
+ public function withAmount(int $amount): self
+ {
+ $this->validateAmount($amount);
+
+ if ($amount === $this->amount) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->amount = $amount;
+ return $clone;
+ }
+
+ public function withCurrency(string $currency): self
+ {
+ $this->validateCurrency($currency);
+
+ if ($currency === $this->currency) {
+ return $this;
+ }
+
+ $clone = clone $this;
+ $clone->currency = $currency;
+ return $clone;
+ }
+
+ public function amount(): int
+ {
+ return $this->amount;
+ }
+
+ public function currency(): string
+ {
+ return $this->currency;
+ }
+
+ public function add(self $money): self
+ {
+ if ($money->currency !== $this->currency) {
+ throw new InvalidArgumentException('Currency mismatch. Cannot add money of different currency.');
+ }
+ return $this->withAmount($this->amount + $money->amount);
+ }
+}
+
+$price = new Money(1000, 'USD');
+$discounted = $price->withAmount(800);
+// $price is still 1000 USD, $discounted is 800 USD
+```
+
+- Kita menandai kelas sebagai `final` untuk mencegah perubahan oleh subclass; sebagai alternatif, rancang ekstensi dengan hati-hati.
+- Lakukan validasi di konstruktor dan metode `with*` sehingga setiap instance selalu valid.
+
+> [!TIP]
+> Jika Anda mendefinisikan DTO sederhana, Anda dapat menggunakan kata kunci `readonly` di PHP modern dan membiarkan properti `public`. Kata kunci `readonly` memastikan properti tidak dapat diubah setelah objek dibuat.
+
+## Menggunakan clone (dan mengapa ini murah)
+
+Clone PHP melakukan salinan dangkal (shallow copy) dari objek. Untuk objek nilai immutable yang hanya berisi skalar
+atau objek immutable lainnya, cloning dangkal sudah cukup dan cepat. Di PHP modern, cloning objek nilai kecil
+murah baik dari segi waktu maupun memori.
+
+Jika objek Anda memegang sub-objek yang mutable dan juga harus disalin, implementasikan `__clone` untuk melakukan deep-clone pada sub-objek tersebut:
+
+```php
+final class Order
+{
+ public function __construct(
+ private Money $total
+ ) {}
+
+ public function total(): Money
+ {
+ return $this->total;
+ }
+
+ public function __clone(): void
+ {
+ // Money is immutable in our example, so a deep clone is not required.
+ // If it were mutable, you could do: $this->total = clone $this->total;
+ }
+
+ public function withTotal(Money $total): self
+ {
+ $clone = clone $this;
+ $clone->total = $total;
+ return $clone;
+ }
+}
+```
+
+## Gaya penggunaan
+
+- Bangun sebuah value object sekali lalu teruskan. Jika Anda perlu mengubahnya, gunakan metode `with*` yang mengembalikan instance baru.
+- Utamakan field skalar/immutable di dalam objek immutable; jika sebuah field dapat berubah, isolasi dan lakukan deep-clone di `__clone` bila diperlukan.
+
+Immutability sejalan dengan preferensi Yii untuk kode yang dapat diprediksi dan bebas efek samping, serta membuat layanan, caching,
+dan konfigurasi menjadi lebih tangguh.
diff --git a/guide/id/databases/db-migrations.md b/guide/id/databases/db-migrations.md
new file mode 100644
index 00000000..0251a2aa
--- /dev/null
+++ b/guide/id/databases/db-migrations.md
@@ -0,0 +1,100 @@
+# Migrasi
+
+Untuk menggunakan migrasi, pasang paket [yiisoft/db-migration](https://github.com/yiisoft/db-migration/):
+
+```shell
+composer require yiisoft/db-migration
+```
+
+### Contoh penggunaan
+
+Pertama, konfigurasikan DI container. Buat `config/common/db.php` dengan isi berikut:
+
+```php
+ [
+ 'class' => SqliteConnection::class,
+ '__construct()' => [
+ 'dsn' => 'sqlite:' . __DIR__ . '/Data/yiitest.sq3'
+ ]
+ ]
+];
+```
+
+Tambahkan hal berikut ke `config/params.php`:
+
+```php
+...
+'yiisoft/db-migration' => [
+ 'newMigrationNamespace' => 'App\\Migration',
+ 'sourceNamespaces' => ['App\\Migration'],
+],
+...
+```
+
+Sekarang tes apakah sudah bekerja:
+
+```shell
+./yii list migrate
+```
+
+### Membuat migrasi
+
+Untuk bekerja dengan migrasi, Anda dapat menggunakan [view](https://github.com/yiisoft/db-migration/tree/master/resources/views) yang disediakan.
+
+```shell
+./yii migrate:create my_first_table --command=table --fields=name,example --table-comment=my_first_table
+```
+
+Perintah tersebut akan menghasilkan file seperti berikut:
+
+```php
+createTable('my_first_table', [
+ 'id' => $b->primaryKey(),
+ 'name',
+ 'example',
+ ]);
+
+ $b->addCommentOnTable('my_first_table', 'dest');
+ }
+
+ public function down(MigrationBuilder $b): void
+ {
+ $b->dropTable('my_first_table');
+ }
+}
+```
+
+Untuk informasi lebih lanjut lihat dokumentasi paket [di sini](https://github.com/yiisoft/db-migration/tree/master/docs/guide/en).
+
+### Migrasi dari Yii2
+
+Migrasi di Yii2 dan paket [yiisoft/db-migration](https://github.com/yiisoft/db-migration/) tidak kompatibel,
+dan tabel `migration` juga tidak kompatibel.
+Solusi yang mungkin adalah menggunakan dump struktur dan mengganti nama tabel `migration` lama. Pada eksekusi awal
+migrasi, tabel `migration` baru dengan field yang baru akan dibuat. Semua perubahan selanjutnya pada skema basis data
+akan diterapkan menggunakan komponen migrasi yang baru dan dicatat di tabel migrasi yang baru.
diff --git a/guide/id/glossary.md b/guide/id/glossary.md
new file mode 100644
index 00000000..be99ef00
--- /dev/null
+++ b/guide/id/glossary.md
@@ -0,0 +1,76 @@
+# A
+
+## alias
+
+Alias adalah sebuah string yang digunakan oleh Yii untuk merujuk ke kelas atau direktori, misalnya `@app/vendor`.
+Baca lebih lanjut di ["Aliases"](concept/aliases.md).
+
+## asset
+
+Aset merujuk pada berkas sumber daya. Biasanya berisi kode JavaScript atau CSS, tetapi bisa berupa konten statis apa pun yang diakses melalui HTTP.
+
+# C
+
+## configuration
+
+Konfigurasi dapat merujuk pada proses mengatur properti suatu objek atau pada berkas konfigurasi yang menyimpan
+pengaturan untuk sebuah objek atau kelas objek. Baca lebih lanjut di ["Configuration"](concept/configuration.md).
+
+# D
+
+## DI
+
+Dependency Injection (Injeksi Dependensi) adalah teknik pemrograman di mana dependensi sebuah objek disediakan (disuntikkan) dari luar. ["DI"](concept/di-container.md)
+
+# I
+
+## installation
+
+Instalasi adalah proses menyiapkan sesuatu agar dapat bekerja, baik dengan mengikuti berkas readme maupun menjalankan skrip
+yang disiapkan khusus. Dalam konteks Yii, ini mencakup pengaturan izin dan pemenuhan persyaratan perangkat lunak.
+
+# M
+
+## middleware
+
+Middleware adalah pemroses dalam tumpukan pemrosesan permintaan (request). Diberikan sebuah request, ia dapat menghasilkan response
+atau melakukan suatu aksi dan meneruskan pemrosesan ke middleware berikutnya. Baca lebih lanjut di ["Middleware"](structure/middleware.md).
+
+## module
+
+Modul adalah sub-aplikasi yang mengelompokkan sejumlah kode berdasarkan suatu kasus penggunaan. Biasanya digunakan di dalam aplikasi utama
+dan dapat berisi handler URL atau perintah konsol.
+
+# N
+
+## namespace
+
+Namespace merujuk pada [fitur bahasa PHP](https://www.php.net/manual/en/language.namespaces.php).
+
+# P
+
+## package
+
+Paket biasanya merujuk pada [paket Composer](https://getcomposer.org/doc/). Ini adalah kode yang siap digunakan ulang dan
+didistribusikan, yang dapat diinstal secara otomatis melalui manajer paket.
+
+# R
+
+## rule
+
+Aturan biasanya merujuk pada aturan validasi dari paket [yiisoft/validator](https://github.com/yiisoft/validator).
+Aturan menyimpan serangkaian parameter untuk memeriksa apakah sebuah himpunan data valid.
+"Rule handler" melakukan pemrosesan sebenarnya.
+
+# Q
+
+## queue
+
+Antrian mirip dengan tumpukan (stack), tetapi mengikuti metodologi First-In-First-Out.
+
+# V
+
+## vendor
+
+Vendor adalah organisasi atau pengembang individu yang menyediakan kode dalam bentuk paket. Istilah ini juga dapat merujuk pada
+direktori `vendor` milik [Composer](https://getcomposer.org/doc/).