= Html::encode($post->getTitle()) ?>
\n" +"= Html::encode($post->getExcerpt()) ?>
\n" +" \n" +"\n" +" = Html::encode($page->text) ?>\n" +"
\n" +"\n" +"= Html::a('Edit', $urlGenerator->generate('page/edit', ['slug' => $page->getSlug()])) ?> |\n" +"\n" +"\n" +"post($urlGenerator->generate('page/delete', ['slug' => $page->getSlug()]))\n" +" ->csrf($csrf);\n" +"?>\n" +"= $deleteForm->open() ?>\n" +" = Html::submitButton('Delete') ?>\n" +"= $deleteForm->close() ?>\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "In this view we have a form that submits a request for page deletion. Handing it with `GET` is common as well, but it is very wrong. Since deletion changes data, it needs to be handled by one of the non-idempotent HTTP methods. We use POST and a form in our example, but it could be `DELETE` and async request made with JavaScript. The button could be later styled properly to look similar to the \"Edit\"." +msgstr "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Delete a page" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/DeleteAction.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"pageRepository->deleteBySlug($slug);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader('Location', $this->urlGenerator->generate('page/list'));\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Create or update a page" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "First of all, we need a form at `src/Web/Page/Form.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"findOneBySlug($slug);\n" +" if ($page === null) {\n" +" return $this->responseFactory->createResponse(Status::NOT_FOUND);\n" +" }\n" +"\n" +" $form->title = $page->title;\n" +" $form->text = $page->text;\n" +" }\n" +"\n" +" $this->formHydrator->populateFromPostAndValidate($form, $request);\n" +"\n" +" if ($form->isValid()) {\n" +" $id = $isNew ? Uuid::uuid7()->toString() : $page->id;\n" +"\n" +" $page = Page::create(\n" +" id: $id,\n" +" title: $form->title,\n" +" text: $form->text,\n" +" updatedAt: new DateTimeImmutable(),\n" +" );\n" +"\n" +" $pageRepository->save($page);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader(\n" +" 'Location',\n" +" $this->urlGenerator->generate('page/view', ['slug' => $page->getSlug()]),\n" +" );\n" +" }\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/edit', [\n" +" 'form' => $form,\n" +" 'isNew' => $isNew,\n" +" 'slug' => $slug,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Note that `Uuid::uuid7()->toString()` won't work for MySQL and you'll need bytes instead, `Uuid::uuid7()->getBytes()`.\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "In the above we use a special slug in the URL for new pages so the URL looks like `http://localhost/pages/new`. If the page isn't new, we pre-fill the form with the data from the database. Similar to how we did in [Working with forms](forms.md), we handle the form submission. After successful save we redirect to the page view." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now, a template in `src/Web/Page/edit.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"post($urlGenerator->generate('page/edit', ['slug' => $slug]))\n" +" ->csrf($csrf);\n" +"?>\n" +"\n" +"= $htmlForm->open() ?>\n" +" = Field::text($form, 'title')->required() ?>\n" +" = Field::textarea($form, 'text')->required() ?>\n" +" = Html::submitButton('Save') ?>\n" +"= $htmlForm->close() ?>\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Routing" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Adjust `config/common/routes.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::methods([Method::GET, Method::POST], '/say')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +"\n" +" Group::create('/pages')->routes(\n" +" Route::get('')\n" +" ->action(Web\\Page\\ListAction::class)\n" +" ->name('page/list'),\n" +" Route::get('/{slug}')\n" +" ->action(Web\\Page\\ViewAction::class)\n" +" ->name('page/view'),\n" +" Route::methods([Method::GET, Method::POST], '/{slug}/edit')\n" +" ->action(Web\\Page\\EditAction::class)\n" +" ->name('page/edit'),\n" +" Route::post('/{slug}/delete')\n" +" ->action(Web\\Page\\DeleteAction::class)\n" +" ->name('page/delete'),\n" +" ),\n" +" ),\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Note that we've grouped all page-related routes with a group under `/pages` prefix. That is a convenient way to both not to repeat yourself and add some extra middleware, such as authentication, to the whole group." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Trying it out" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now try it out by opening `http://localhost/pages` in your browser." +msgstr "" diff --git a/_translations/po/zh-CN/guide_start_forms.md.po b/_translations/po/zh-CN/guide_start_forms.md.po new file mode 100644 index 00000000..ac03eea3 --- /dev/null +++ b/_translations/po/zh-CN/guide_start_forms.md.po @@ -0,0 +1,338 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Working with forms" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "This section continues to improve on \"Saying Hello.\" Instead of using URL, you will now ask a user for a message via form." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Through this tutorial, you will learn how to:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Create a form model to represent the data entered by a user through a form." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Declare rules to validate the data entered." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Build an HTML form in a view." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Installing form package" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To install form package, issue the following command in your application directory:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "composer require yiisoft/form-model\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "For Docker that would be:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "make composer require yiisoft/form-model\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Creating a form " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "The data to be requested from the user will be represented by a `Form` class as shown below and saved in the file `/src/App/Web/Echo/Form.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +" " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Now that you have a form, use it in your action from \"[Saying Hello](hello.md)\"." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Here's what you end up with in `/src/Web/Echo/Action.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"formHydrator->populateFromPostAndValidate($form, $request);\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/template', [\n" +" 'form' => $form,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Instead of reading from route, you fill your form from request's POST data and validate it with the help of `FormHydrator`. Next you pass the form to the view." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "For the form to function we need to allow both GET to render the form and POST to send the data. Adjust your route in `config/common/routes.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::methods([Method::GET, Method::POST], '/say')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +" ),\n" +"];\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Adjusting view" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To render a form, you need to change your view, `src/Web/Echo/template.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"post($urlGenerator->generate('echo/say'))\n" +" ->csrf($csrf);\n" +"?>\n" +"\n" +"= $htmlForm->open() ?>\n" +" = Field::text($form, 'message')->required() ?>\n" +" = Html::submitButton('Say') ?>\n" +"= $htmlForm->close() ?>\n" +"\n" +"isValid()): ?>\n" +" Echo said: = Html::encode($form->message) ?>\n" +"\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "If the form is valid, you display a message. The rest initializes and renders the form." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "First, you initialize `$htmlForm` with the POST type and the action URL generated with the help from the URL generator. You can access it as `$urlGenerator` in all views. You also need to pass the CSRF token to the form, which is also available in every view as `$csrf` thanks to the view injections listed in `config/common/params.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"'yiisoft/yii-view-renderer' => [\n" +" 'injections' => [\n" +" Reference::to(CsrfViewInjection::class),\n" +" ],\n" +"],\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "The template renders the CSRF token value as a hidden input to ensure that the request originates from the form page and not from another website. It will be submitted along with POST form data. Omitting it would result in [HTTP response code 422](https://tools.ietf.org/html/rfc4918#section-11.2)." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "You use `Field::text()` to output \"message\" field, so it takes care about filling the value, escaping it, rendering field label and validation errors." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Now, in case you submit an empty message, you will get a validation error: \"The message to be echoed must contain at least 2 characters.\"" +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Trying it Out " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To see how it works, use your browser to access the following URL:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "http://localhost:8080/say\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "You will see a page with a form input field and a label that indicates what data to enter. Also, the form has a \"submit\" button labeled \"Say\". If you click the \"submit\" button without entering anything, you will see that the field is required. If you enter a single character, the form displays an error message next to the problematic input field." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "After you enter a valid message and click the \"submit\" button, the page echoes the data that you entered." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "" +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#, no-wrap +msgid "Summary " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "In this section of the guide, you've learned how to create a form model class to represent the user data and validate said data." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "You've also learned how to get data from users and how to display data back in the browser. This is a task that could take you a lot of time when developing an application, but Yii provides powerful widgets to make this task easy." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "In the next section, you will learn how to work with databases, which are needed in nearly every application." +msgstr "" diff --git a/_translations/po/zh-CN/guide_start_gii.md.po b/_translations/po/zh-CN/guide_start_gii.md.po new file mode 100644 index 00000000..405dcb67 --- /dev/null +++ b/_translations/po/zh-CN/guide_start_gii.md.po @@ -0,0 +1,22 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/gii.md +#, no-wrap +msgid "Generating code with Gii" +msgstr "" diff --git a/_translations/po/zh-CN/guide_start_hello.md.po b/_translations/po/zh-CN/guide_start_hello.md.po new file mode 100644 index 00000000..a3fc2edc --- /dev/null +++ b/_translations/po/zh-CN/guide_start_hello.md.po @@ -0,0 +1,284 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-25 21:55+0000\n" +"PO-Revision-Date: 2025-12-25 21:55+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#, no-wrap +msgid "Summary " +msgstr "" + +#. type: Title # +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Saying hello" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "This section describes how to create a new \"Hello\" page in your application. It's a simple page that will echo back whatever you pass to it or, if nothing passed, will just say \"Hello!\"." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "To achieve this goal, you will define a route and create [a handler](../structure/handler.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Through this tutorial, you will learn three things:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/guide/start/hello.md +msgid "How to create a handler to respond to a request." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/start/hello.md +msgid "How to map URL to the handler." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/start/hello.md +msgid "How to use [view](../views/view.md) to compose the response's content." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Creating a handler " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "For the \"Hello\" task, you will create a handler class that reads a `message` parameter from the request and displays that message back to the user. If the request doesn't provide a `message` parameter, the action will display the default \"Hello\" message." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Create `src/Web/Echo/Action.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md +#, no-wrap +msgid "" +"responseFactory->createResponse();\n" +" $response->getBody()->write('The message is: ' . Html::encode($message));\n" +" return $response;\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In your example, the `__invoke` method receives the `$message` parameter that with the help of `RouteArgument` attribute gets the message from URL. The value defaults to `\"Hello!\"`. If the request is made to `/say/Goodbye`, the action assigns the value \"Goodbye\" to the `$message` variable." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "The application passes the response through the [middleware stack](../structure/middleware.md) to the emitter that outputs the response to the end user." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Configuring router" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Now, to map your handler to URL, you need to add a route in `config/common/routes.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::get('/say[/{message}]')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +" ),\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In the above, you map the `/say[/{message}]` pattern to `\\App\\Web\\Echo\\Action`. For a request, the router creates an instance and calls the `__invoke()` method. The `{message}` part of the pattern writes anything specified in this place to the `message` request attribute. `[]` marks this part of the pattern as optional." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "You also give a `echo/say` name to this route to be able to generate URLs pointing to it." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Trying it out " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "After creating the action and the view open `http://localhost/say/Hello+World` in your browser." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "This URL displays a page with \"The message is: Hello World\"." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "If you omit the `message` parameter in the URL, the page displays \"The message is: Hello!\"." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Creating a View Template " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Usually, the task is more complicated than printing out \"hello world\" and involves rendering some complex HTML. For this task, it's handy to use view templates. They're scripts you write to generate a response's body." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "For the \"Hello\" task, create a `src/Web/Echo/template.php` template that prints the `message` parameter received from the action method:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md ../src/guide/views/view.md +#, no-wrap +msgid "" +"\n" +"\n" +"The message is: = Html::encode($message) ?>
\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In the above code, the `message` parameter uses HTML encoding before you print it. You need that because the parameter comes from an end user and is vulnerable to [cross-site scripting (XSS) attacks](https://en.wikipedia.org/wiki/Cross-site_scripting) by embedding malicious JavaScript in the parameter." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Naturally, you may put more content in the `say` view. The content can consist of HTML tags, plain text, and even PHP statements. In fact, the view service executes the `say` view as a PHP script." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "To use the view, you need to change `src/Web/Echo/Action.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'message' => $message,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Now open your browser and check it again. You should see the similar text but with a layout applied." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Also, you've separated the part about how it works and part of how it's presented. In the larger applications, it helps a lot to deal with complexity." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In this section, you've touched the handler and template parts of the typical web application. You created a handler as part of a class to handle a specific request. You also created a view to compose the response's content. In this simple example, no data source was involved as the only data used was the `message` parameter." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "You've also learned about routing in Yii, which acts as the bridge between user requests and handlers." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In the next section, you will learn how to fetch data and add a new page containing an HTML form." +msgstr "" diff --git a/_translations/po/zh-CN/guide_start_looking-ahead.md.po b/_translations/po/zh-CN/guide_start_looking-ahead.md.po new file mode 100644 index 00000000..2b094e1a --- /dev/null +++ b/_translations/po/zh-CN/guide_start_looking-ahead.md.po @@ -0,0 +1,27 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/looking-ahead.md +#, no-wrap +msgid "Looking ahead" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/looking-ahead.md +msgid "If you've read through the entire \"Getting Started\" chapter, you have now created a complete Yii application. In the process, you've learned how to implement some commonly necessary features, such as getting data from users via an HTML form, fetching data from a database, and displaying data in a paginated fashion. You've also learned how to use [Gii](gii.md) to generate code automatically. Using Gii for code generation turns the bulk of your Web development process into a task as simple as just filling out some forms." +msgstr "" diff --git a/_translations/po/zh-CN/guide_start_prerequisites.md.po b/_translations/po/zh-CN/guide_start_prerequisites.md.po new file mode 100644 index 00000000..643f9b01 --- /dev/null +++ b/_translations/po/zh-CN/guide_start_prerequisites.md.po @@ -0,0 +1,97 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Docker" +msgstr "" + +#. type: Title # +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "What do you need to know?" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "The Yii learning curve isn't as steep as other PHP frameworks, but still, there are some things you should learn before starting with Yii." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "PHP" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Yii is a PHP framework, so make sure you [read and understand language reference](https://www.php.net/manual/en/langref.php)." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Object-oriented programming" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "You need a basic understanding of object-oriented programming. If you're not familiar with it, check one of the many tutorials available such as [the one from tuts+](https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762)." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "When you develop with Yii, you write code in an object-oriented fashion, so make sure you're familiar with [PHP OOP support](https://www.php.net/manual/en/language.oop5.php)." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Note that the more complicated your application is, the more advanced OOP concepts you should learn to successfully manage that complexity." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Command line and Composer" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Yii extensively uses the de-facto standard PHP package manager, [Composer](https://getcomposer.org) so make sure you read and understand its [guide](https://getcomposer.org/doc/01-basic-usage.md). If you aren't familiar with using the command line, it's time to start trying. Once you learn the basics, you'll never want to work without it." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "HTTP" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Since Yii is a web framework and the web largely uses HTTP, it's a good idea to [learn more about it](https://developer.mozilla.org/en-US/docs/Web/HTTP)." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "The default application template leverages Docker, so we recommend that you [read and understand the concepts](https://docs.docker.com/get-started/)." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Also, you will benefit from familiarizing yourself with [twelve-factor app](https://12factor.net/) principles." +msgstr "" diff --git a/_translations/po/zh-CN/guide_start_workflow.md.po b/_translations/po/zh-CN/guide_start_workflow.md.po new file mode 100644 index 00000000..41f1fa1d --- /dev/null +++ b/_translations/po/zh-CN/guide_start_workflow.md.po @@ -0,0 +1,193 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Running applications" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "After installing Yii, you have a working Yii application. This section introduces the application's built-in functionality, how the code is organized, and how the application handles requests in general." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Note that unlike the framework itself, after you install a project template, it's all yours. You're free to add or delete code and overall change it as you need." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Functionality " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The installed application contains only one page, accessible at `http://localhost/`. It shares a common layout that you can reuse on further pages." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "In addition to the web application, you can access a console script via `APP_ENV=dev ./yii` or, in case of Docker, `make yii`. Use this script to run background and maintenance tasks for the application, which the [Console Application Section](../tutorial/console-applications.md) describes." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Application structure " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The most important directories and files in your application are (assuming the application's root directory is `app`):" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"assets/ Asset bundle source files.\n" +"config/ Configuration files.\n" +" common/ Common configuration and DI definitions.\n" +" console/ Console-specific configuration.\n" +" environments/ Environment-specific configuration (dev/test/prod).\n" +" web/ Web-specific configuration.\n" +"docker/ Docker-specific files.\n" +"public/ Files publically accessible from the Internet.\n" +" assets/ Published/compiled assets.\n" +" index.php Entry script.\n" +"runtime/ Files generated during runtime.\n" +"src/ Application source code.\n" +" Console/ Console commands.\n" +" Shared/ Code shared between web and console applications.\n" +" Web/ Web-specific code (actions, handlers, layout).\n" +" Shared/ Shared web components.\n" +" Layout/ Layout components and templates.\n" +" Environment.php Environment configuration class.\n" +"tests/ A set of Codeception tests for the application.\n" +" Console/ Console command tests.\n" +" Functional/ Functional tests.\n" +" Unit/ Unit tests.\n" +" Web/ Web actions tests.\n" +"vendor/ Installed Composer packages.\n" +"Makefile Config for make command.\n" +"yii Console application entry point.\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "In general, the files in the application fall into two groups: those under `app/public` and those under other directories. You can access the former directly via HTTP (i.e., in a browser), while you shouldn't expose the latter." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Each application has an entry script `public/index.php`, the only web-accessible PHP script in the application. The entry script uses an [application runner](https://github.com/yiisoft/yii-runner) to create an instance of an incoming request with the help of one of PSR-7 packages and passes it to an [application](../structure/application.md) instance. The application executes a set of middleware sequentially to process the request. It then passes the result to the emitter, which sends the response to the browser." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Depending on the middleware you use, the application may behave differently. By default, a router uses the requested URL and configuration to choose a handler and execute it to produce a response." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "You can learn more about the application template from the [yiisoft/app package documentation](https://github.com/yiisoft/app/blob/master/README.md)." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Request Lifecycle " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The following diagram shows how an application handles a request." +msgstr "" + +#. type: Fenced code block (mermaid) +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"flowchart LR\n" +" user[User's client] --> index\n" +" index[index.php] --> DI[Initialize Dependency Container]\n" +" config[configs] -.-> DI\n" +" DI --> RequestFactory[RequestFactory]\n" +" RequestFactory -->|Request| app[Application]\n" +" app -->|Request| middleware[Middleware]\n" +" middleware -->|Request| router[Router]\n" +" router -->|Request| action[Action Handler]\n" +" action -->|Response| emitter[SapiEmitter]\n" +" router -->|Response| emitter\n" +" middleware -->|Response| emitter\n" +" app -->|Response| emitter\n" +" emitter --> user\n" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/guide/start/workflow.md +msgid "A user makes a request to the [entry script](../structure/entry-script.md) `public/index.php`." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/start/workflow.md +msgid "The entry script with the help of the application runner loads the container [configuration](../concept/configuration.md) and creates an [application](../structure/application.md) instance and services necessary to handle the request." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/start/workflow.md +msgid "Request factory creates a request object based on a raw request that came from a user." +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/guide/start/workflow.md +msgid "Application passes a request object through a middleware array configured. One of these is typically a router." +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/guide/start/workflow.md +msgid "The Router finds out what handler to execute based on request and configuration." +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/guide/start/workflow.md +msgid "The handler may load some data, possibly from a database." +msgstr "" + +#. type: Bullet: '7. ' +#: ../src/guide/start/workflow.md +msgid "The handler forms a response by using data. Either directly or with the help of the view package." +msgstr "" + +#. type: Bullet: '8. ' +#: ../src/guide/start/workflow.md +msgid "Emitter receives the response and takes care of sending the response to the user's browser." +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_action.md.po b/_translations/po/zh-CN/guide_structure_action.md.po new file mode 100644 index 00000000..ce452a9b --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_action.md.po @@ -0,0 +1,178 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-13 16:53+0000\n" +"PO-Revision-Date: 2026-01-13 16:53+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/action.md +#, no-wrap +msgid "Actions" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "In a web application, the request URL determines what's executed. Matching is made by a router configured with multiple routes. Each route can be attached to a middleware that, given request, produces a response. Since middleware overall could be chained and can pass actual handling to the next middleware, we call the middleware actually doing the job an action." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "There are multiple ways to describe an action. The simplest one is using a closure:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/')->action(function (ServerRequestInterface $request) use ($responseFactory): ResponseInterface {\n" +" $response = $responseFactory->createResponse();\n" +" $response->getBody()->write('You are at homepage.');\n" +" return $response;\n" +"});\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "It's fine for simple handling since any more complicated one would require getting dependencies, so a good idea would be moving the handling to a class method. Callback middleware could be used for the purpose:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/')->action(FrontPageAction::class),\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "The class itself would be like:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class FrontPageAction\n" +"{\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // build response for a front page \n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "For many cases, it makes sense to group handling for many routes into a single class:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/post/index')->action([PostController::class, 'actionIndex']),\n" +"Route::get('/post/view/{id:\\d+}')->action([PostController::class, 'actionView']),\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "The class itself would look like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function actionIndex(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // render posts list\n" +" }\n" +" \n" +" \n" +" public function actionView(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // render a single post \n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "We usually call such a class \"controller.\"" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/action.md +#, no-wrap +msgid "Autowiring" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"Both constructors of action-classes and action-methods are automatically getting services from\n" +" the dependency injection container:\n" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function __construct(\n" +" private PostRepository $postRepository\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function actionIndex(ServerRequestInterface $request, LoggerInterface $logger): ResponseInterface\n" +" {\n" +" $logger->debug('Rendering posts list');\n" +" // render posts list\n" +" }\n" +" \n" +" \n" +" public function actionView(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // render a single post \n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "In the above example `PostRepository` is injected automatically via constructor. That means it is available in every action. Logger is injected into `index` action only." +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_application.md.po b/_translations/po/zh-CN/guide_structure_application.md.po new file mode 100644 index 00000000..fde4bda9 --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_application.md.po @@ -0,0 +1,47 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-27 03:24+0000\n" +"PO-Revision-Date: 2025-12-27 03:24+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/application.md +#, no-wrap +msgid "Application" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/application.md +msgid "The primary purpose of the web application and its runner in Yii3 is to process requests to get responses." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/application.md +msgid "Typically, the runtime consists of:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/guide/structure/application.md +msgid "Startup. Get config, create an instance of container and do additional environment initialization such as registering error handler, so it can handle errors occurring. Fire `ApplicationStartup` event." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/structure/application.md +msgid "Handle requests via passing request objects to middleware dispatcher to execute [middleware stack](middleware.md) and get a response object. In usual PHP applications, it's done once. In [environments such as RoadRunner](../tutorial/using-with-event-loop.md), it could be done multiple times with the same application instance. Response object is converted into an actual HTTP response by using emitter. Fire `AfterEmit` event." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/structure/application.md +msgid "Shutdown. Fire `ApplicationShutdown` event." +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_domain.md.po b/_translations/po/zh-CN/guide_structure_domain.md.po new file mode 100644 index 00000000..d4fee0d0 --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_domain.md.po @@ -0,0 +1,190 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +#: ../src/guide/concept/autoloading.md ../src/guide/security/best-practices.md +#: ../src/guide/structure/domain.md +#: ../src/guide/tutorial/console-applications.md +#: ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md +#: ../src/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md ../src/guide/structure/domain.md +#: ../src/guide/structure/service.md +#, no-wrap +msgid "Repository" +msgstr "" + +#. type: Title # +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Domain" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "" +"The Domain or domain model is what makes the project unique. With requirements and terminology of the problem being solved\n" +"in mind (the problem context), you build an abstraction that consists of entities, their relationships, and logic that\n" +"operates these entities. To focus on the complex part of the problem, domain is, ideally, separated from\n" +" the infrastructure part of the system (that's how to save data into a database, how to form HTTP response, etc.).\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> Such isolation is suitable for complex systems. If your project domain is basically create/read/update/delete\n" +"> for a set of records with not much complex logic, it makes no sense to apply a complex solution to a simple problem.\n" +"> The individual concepts of domain design below could be applied separately, so make sure to check these even if your\n" +"> project isn't that complicated. \n" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Bounded context" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "It's nearly impossible to build a model that solves multiple problems that aren't too complicated by itself. Therefore, it's a good practice to divide the domain into several use-cases and have a separate model for each use-case. Such separated models are called \"bounded contexts.\"" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Building blocks" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "There are various building blocks that are typically used when describing domain models. It isn't mandatory to use them all." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/domain.md ../src/guide/structure/service.md +#, no-wrap +msgid "Entity" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "Entity is a uniquely identifiable object such as user, product, payment, etc. When comparing them, you're checking ID, not the attribute values. If there are two objects with different attributes but the same ID, they're considered being the same thing." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Value object" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "Value object describes an object by its characteristics. For example, a price that consists of value and currency. When comparing such objects, you're checking actual values. If they match, an object is considered to be the same." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Aggregate" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "Aggregate is a set of domain objects such as entities and value objects and additional data that could be treated as a single unit. It usually represents a compound object from a domain model such as shop order or HR person dossier." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "One of the components of an aggregate is called a root. The root identifies an aggregate as a whole and should be used to access it." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Domain event" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "An aggregate, while processed, may raise events. For example, when order is confirmed, `OrderConfirmed` event would be risen so other parts of the system may react on these." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Data transfer object" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "Data transfer object or DTO is an object whose only purpose is to hold data as it is. It's commonly used to pass data between different services." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Service" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "Service is a class that contains a standalone operation within the context of your domain model. See \"[service components](service.md)\"." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "The repository task is to abstract away how domain objects are obtained. These are usually separated into two parts: an interface that stays in the domain layer and an implementation that's situated in the infrastructure layer. In such a way, domain doesn't care how data is obtained and saved and may be focused around the complicated business logic instead." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "Repository is usually implemented as a service." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/domain.md +#, no-wrap +msgid "Instantiating building blocks" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/domain.md +msgid "Entity, value object, aggregate, and domain events aren't services and shouldn't be instantiated through DI container. Using `new` is the way to go with these." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/domain.md +msgid "[BoundedContext by Martin Fowler](https://martinfowler.com/bliki/BoundedContext.html)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/domain.md +msgid "[ValueObject by Martin Fowler](https://martinfowler.com/bliki/ValueObject.html)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/domain.md +msgid "[Aggregate by Marting Fowler](https://martinfowler.com/bliki/DDD_Aggregate.html)" +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_entry-script.md.po b/_translations/po/zh-CN/guide_structure_entry-script.md.po new file mode 100644 index 00000000..00539229 --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_entry-script.md.po @@ -0,0 +1,192 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Entry scripts" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry scripts are the first step in the application bootstrapping process. An application (either Web application or console application) has a single entry script. End users make requests to entry scripts which instantiate application instances and forward the requests to them." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry scripts for Web applications must be stored under Web-accessible directories so that they can be accessed by end users. They're often named as `index.php`, but can also use any other names, provided Web servers can locate them." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry script for console application is `./yii`." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry scripts mainly perform the following work with the help of `ApplicationRunner`:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Register [Composer autoloader](https://getcomposer.org/doc/01-basic-usage.md#autoloading);" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Obtain configuration;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Use configuration to initialize a dependency injection container;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Get an instance of the request." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Pass it to `Application` to handle and get a response from it." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "With the help of an emitter that transforms a response object into an actual HTTP response that's sent to the client browser." +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Web Applications " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "The following is the code in the entry script for the application template:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "" +"debug();\n" +"// Run application:\n" +"$runner->run();\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Console Applications " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Similarly, the following is the code for the entry script of a console application:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "" +"#!/usr/bin/env php\n" +"withDefinitions($config->get('console'))\n" +" ->withProviders($config->get('providers-console'));\n" +"$container = new Container($containerConfig);\n" +"\n" +"/** @var ContainerInterface $container */\n" +"$container = $container->get(ContainerInterface::class);\n" +"\n" +"$application = $container->get(Application::class);\n" +"$exitCode = 1;\n" +"\n" +"try {\n" +" $application->start();\n" +" $exitCode = $application->run(null, new ConsoleBufferedOutput());\n" +"} catch (\\Error $error) {\n" +" $application->renderThrowable($error, new ConsoleBufferedOutput());\n" +"} finally {\n" +" $application->shutdown($exitCode);\n" +" exit($exitCode);\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Alternative runtimes" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "For alternative runtimes such as RoadRunner or Swoole, special entry scripts should be used. See:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/entry-script.md +msgid "[Using Yii with RoadRunner](../tutorial/using-yii-with-roadrunner.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/entry-script.md +msgid "[Using Yii with Swoole](../tutorial/using-yii-with-swoole.md)" +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_middleware.md.po b/_translations/po/zh-CN/guide_structure_middleware.md.po new file mode 100644 index 00000000..f133d097 --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_middleware.md.po @@ -0,0 +1,315 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-10 14:31+0000\n" +"PO-Revision-Date: 2026-01-10 14:31+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Middleware" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Yii works with HTTP using the abstraction layer built around [PSR-7 HTTP message interfaces](https://www.php-fig.org/psr/psr-7/) and [PSR-15 request handler/middleware interfaces](https://www.php-fig.org/psr/psr-15/)." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "The application is composed of one or several middleware. Middleware runs between request and response. When the URL is requested, the request object is passed to the middleware dispatcher that starts executing middleware one after another. Each middleware, given the request, can:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/middleware.md +msgid "Pass the request to the next middleware performing some work before / after it." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/middleware.md +msgid "Form the response and return it." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Depending on middleware used, application behavior may vary significantly." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "In the above each next middleware wraps the previous middleware. Alternatively, it could be presented as follows:" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Using middleware" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Any [PSR-15](https://www.php-fig.org/psr/psr-15/) compatible middleware could be used with Yii, and there are many. Say, you need to add basic authentication to one of the application URLs. URL-dependent middleware is configured using router, so you need to change the router factory." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Authentication middleware is implemented by `middlewares/http-authentication` package so execute `composer require middlewares/http-authentication` in the application root directory." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Now register the middleware in DI container configuration `config/web.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +" [\n" +" 'class' => \\Middlewares\\BasicAuthentication::class,\n" +" '__construct()' => [\n" +" 'users' => [\n" +" 'foo' => 'bar',\n" +" ],\n" +" ],\n" +" 'realm()' => ['Access to the staging site via basic auth'],\n" +" 'attribute()' => ['username'],\n" +"],\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "In the `config/routes.php`, add new route:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"action([SiteController::class, 'auth'])\n" +" ->name('site/auth')\n" +" ->prependMiddleware(BasicAuthentication::class)\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "When configuring routing, you're binding `/basic-auth` URL to a chain of middleware consisting of basic authentication, and the action itself. A chain is a special middleware that executes all the middleware it's configured with." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "The action itself could be the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"public function auth(ServerRequestInterface $request): ResponseInterface\n" +"{\n" +" $response = $this->responseFactory->createResponse();\n" +" $response->getBody()->write('Hi ' . $request->getAttribute('username'));\n" +" return $response;\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Basic authentication middleware wrote to request `username` attribute, so you can access the data if needed." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To apply middleware to application overall regardless of URL, adjust `config/application.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"return [\n" +" Yiisoft\\Yii\\Http\\Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to(static function (Injector $injector) {\n" +" return ($injector->make(MiddlewareDispatcher::class))\n" +" ->withMiddlewares(\n" +" [\n" +" ErrorCatcher::class,\n" +" BasicAuthentication::class,\n" +" SessionMiddleware::class,\n" +" CsrfMiddleware::class,\n" +" Router::class,\n" +" ]\n" +" );\n" +" }),\n" +" 'fallbackHandler' => Reference::to(NotFoundHandler::class),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Creating your own middleware" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To create middleware, you need to implement a single `process` method of `Psr\\Http\\Server\\MiddlewareInterface`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "There are multiple ways to handle a request, and choosing one depends on what the middleware should achieve." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Forming a response directly" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To respond directly, one needs a response factory passed via constructor:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"responseFactory->createResponse();\n" +" $response->getBody()->write('Hello!');\n" +" return $response;\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Delegating handling to the next middleware" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"If middleware either isn't intended to form a response or change the request or can't do anything this time,\n" +"handling could be left to the next middleware in the stack: \n" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n" +"{\n" +" return $handler->handle($request); \n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "In case you need to pass data to the next middleware, you can use request attributes:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"$request = $request->withAttribute('answer', 42);\n" +"return $handler->handle($request);\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To get it in the next middleware:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "$answer = $request->getAttribute('answer');\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Capturing response to manipulate it" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "You may want to capture the response to manipulate it. It could be useful for adding CORS headers, gzipping content, etc." +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"$response = $handler->handle($request);\n" +"// extra handing\n" +"return $response;\n" +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_overview.md.po b/_translations/po/zh-CN/guide_structure_overview.md.po new file mode 100644 index 00000000..f43dd389 --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_overview.md.po @@ -0,0 +1,160 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/structure/overview.md +#: ../src/en/guide/views/script-style-meta.md +#, no-wrap +msgid "Overview" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "Yii applications code is typically grouped into modules by context. In each module there could be grouping by type." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "For example, if the application is an online store, the context could be:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Customer" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Profile" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Products list" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Checkout" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Logistics" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Delivery" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Addresses" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Helpdesk" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Support" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Claims" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Returns" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Accounting" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Transactions" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Taxes" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "For a \"Customer\" context, residing under `App\\Customer` namespace, structure would be:" +msgstr "" + +#. type: Fenced code block +#: ../src/en/guide/structure/overview.md +#, no-wrap +msgid "" +"App/\n" +" Customer/ <-- module namespace\n" +" Entity/\n" +" Customer.php <-- entity shared by \"Profile\" and \"Checkout\"\n" +" Profile/\n" +" Widget/\n" +" Gravatar.php\n" +" ProfileRepository.php <-- repository is usually specific to context\n" +" ProfileController.php <-- \"Customer\\Profile\" entry point\n" +" ProductList/ <-- module namespace \n" +" Entity/ <-- entities specific to \"Customer\\ProductList\"\n" +" Category.php\n" +" Product.php\n" +" ProductsListController.php <-- \"Customer\\ProductList\" entry point\n" +" Checkout/ <-- module namespace\n" +" CheckoutController.php\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "A context may include sub-contexts. If a class is shared by multiple contexts, it's moved to the ancestor of both contexts." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "Besides, Yii applications also have the following:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/en/guide/structure/overview.md +msgid "[entry scripts](entry-script.md): they're PHP scripts that are directly accessible by end users. They're responsible for starting a request handling cycle. Typically, a single entry script is handling the whole application." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/en/guide/structure/overview.md +msgid "[services](service.md): they're typically stateless objects registered within dependency container and provide various action methods." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/en/guide/structure/overview.md +msgid "[middleware](middleware.md): they represent a code that needs to be invoked before and after the actual handling of each request by action handlers." +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_package.md.po b/_translations/po/zh-CN/guide_structure_package.md.po new file mode 100644 index 00000000..f93aae08 --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_package.md.po @@ -0,0 +1,341 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Packages" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Reusable code could be released as [a Composer package](https://getcomposer.org/doc/05-repositories.md#package). It could be an infrastructure library, a module representing one of the application contexts or, basically, any reusable code." +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Using packages " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "By default, Composer installs packages registered on [Packagist](https://packagist.org/) — the biggest repository for open source PHP packages. You can look for packages on Packagist. You may also [create your own repository](https://getcomposer.org/doc/05-repositories.md#repository) and configure Composer to use it. This is useful if you're developing private packages that you want to share within your projects only." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Packages installed by Composer are stored in the `vendor` directory of your project. Because the Composer is a dependency manager, when it installs a package, it will also install all its dependent packages." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> `vendor` directory of your application should never be modified.\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "A package could be installed with the following command:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/structure/package.md +#, no-wrap +msgid "composer install vendor-name/package-name\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "After it's done, Composer modifies `composer.json` and `composer.lock`. The former defines what packages to install, and their version constraints the latter stores a snapshot of exact versions actually installed." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Classes from the package will be available immediately via [autoloading](../concept/autoloading.md)." +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Creating packages " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "You may consider creating a package when you feel the need to share with other people your great code. A package can contain any code you like, such as a helper class, a widget, a service, middleware, the whole module, etc." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Below are the basic steps you may follow." +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/guide/structure/package.md +msgid "Create a project for your package and host it on a VCS repository, such as [GitHub.com](https://github.com). The development and maintenance work for the package should be done on this repository." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/structure/package.md +msgid "Under the root directory of the project, create a file named `composer.json` as required by Composer. Please refer to the next subsection for more details." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/structure/package.md +msgid "Register your package with a Composer repository, such as [Packagist](https://packagist.org/), so that other users can find and install your package using Composer." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "`composer.json` " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Each Composer package must have a `composer.json` file in its root directory. The file contains the metadata about the package. You may find the complete specification about this file in the [Composer Manual](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup). The following example shows the `composer.json` file for the `yiisoft/yii-widgets` package:" +msgstr "" + +#. type: Fenced code block (json) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "" +"{\n" +" \"name\": \"yiisoft/yii-widgets\",\n" +" \"type\": \"library\",\n" +" \"description\": \"Yii widgets collection\",\n" +" \"keywords\": [\n" +" \"yii\",\n" +" \"widgets\"\n" +" ],\n" +" \"homepage\": \"https://www.yiiframework.com/\",\n" +" \"license\": \"BSD-3-Clause\",\n" +" \"support\": {\n" +" \"issues\": \"https://github.com/yiisoft/yii-widgets/issues?state=open\",\n" +" \"forum\": \"https://www.yiiframework.com/forum/\",\n" +" \"wiki\": \"https://www.yiiframework.com/wiki/\",\n" +" \"irc\": \"ircs://irc.libera.chat:6697/yii\",\n" +" \"chat\": \"https://t.me/yii3en\",\n" +" \"source\": \"https://github.com/yiisoft/yii-widgets\"\n" +" },\n" +" \"funding\": [\n" +" {\n" +" \"type\": \"opencollective\",\n" +" \"url\": \"https://opencollective.com/yiisoft\"\n" +" },\n" +" {\n" +" \"type\": \"github\",\n" +" \"url\": \"https://github.com/sponsors/yiisoft\"\n" +" }\n" +" ],\n" +" \"require\": {\n" +" \"php\": \"^7.4|^8.0\",\n" +" \"yiisoft/aliases\": \"^1.1|^2.0\",\n" +" \"yiisoft/cache\": \"^1.0\",\n" +" \"yiisoft/html\": \"^2.0\",\n" +" \"yiisoft/view\": \"^4.0\",\n" +" \"yiisoft/widget\": \"^1.0\"\n" +" },\n" +" \"require-dev\": {\n" +" \"phpunit/phpunit\": \"^9.5\",\n" +" \"roave/infection-static-analysis-plugin\": \"^1.16\",\n" +" \"spatie/phpunit-watcher\": \"^1.23\",\n" +" \"vimeo/psalm\": \"^4.18\",\n" +" \"yiisoft/psr-dummy-provider\": \"^1.0\",\n" +" \"yiisoft/test-support\": \"^1.3\"\n" +" },\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"Yiisoft\\\\Yii\\\\Widgets\\\\\": \"src\"\n" +" }\n" +" },\n" +" \"autoload-dev\": {\n" +" \"psr-4\": {\n" +" \"Yiisoft\\\\Yii\\\\Widgets\\\\Tests\\\\\": \"tests\"\n" +" }\n" +" },\n" +" \"extra\": {\n" +" \"branch-alias\": {\n" +" \"dev-master\": \"3.0.x-dev\"\n" +" }\n" +" },\n" +" \"scripts\": {\n" +" \"test\": \"phpunit --testdox --no-interaction\",\n" +" \"test-watch\": \"phpunit-watcher watch\"\n" +" },\n" +" \"config\": {\n" +" \"sort-packages\": true,\n" +" \"allow-plugins\": {\n" +" \"infection/extension-installer\": true,\n" +" \"composer/package-versions-deprecated\": true\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title #### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Package Name " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Each Composer package should have a package name which uniquely identifies the package among all others. The format of package names is `vendorName/projectName`. For example, in the package name `yiisoft/queue`, the vendor name, and the project name are `yiisoft` and `queue`, respectively." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> Don't use `yiisoft` as your vendor name as it's reserved for use by the Yii itself.\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "We recommend you prefix `yii-` to the project name for packages that aren't able to work as general PHP packages and require Yii application. This will allow users to more easily tell whether a package is Yii specific." +msgstr "" + +#. type: Title #### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Dependencies " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "If your extension depends on other packages, you should list them in `require` section of `composer.json`. Make sure you also list appropriate version constraints (e.g. `^1.0`, `@stable`) for each dependent package. Use stable dependencies when your extension is released in a stable version." +msgstr "" + +#. type: Title #### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Class Autoloading " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "In order for your classes to be autoloaded, you should specify the `autoload` entry in the `composer.json` file, like shown below:" +msgstr "" + +#. type: Fenced code block (json) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "" +"{\n" +" // ....\n" +"\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"MyVendorName\\\\MyPackageName\\\\\": \"src\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "You may list one or multiple root namespaces and their corresponding file paths." +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Recommended Practices " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Because packages are meant to be used by other people, you often need to make an extra effort during development. Below, we introduce some common and recommended practices in creating high-quality extensions." +msgstr "" + +#. type: Title #### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Testing " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "You want your package to run flawlessly without bringing problems to other people. To reach this goal, you should test your extension before releasing it to the public." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "It's recommended that you create various test cases to cover your extension code rather than relying on manual tests. Each time before you release a new version of your package, you may run these test cases to make sure everything is in good shape. For more details, please refer to the [Testing](../testing/overview.md) section." +msgstr "" + +#. type: Title #### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Versioning " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "You should give each release of your extension a version number (e.g. `1.0.1`). We recommend you follow the [semantic versioning](https://semver.org) practice when determining what version numbers should be used." +msgstr "" + +#. type: Title #### +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Releasing " +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "To let other people know about your package, you need to release it to the public." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "If it's the first time you're releasing a package, you should register it in a Composer repository, such as [Packagist](https://packagist.org/). After that, all you need to do is create a release tag (for example, `v1.0.1`) on the VCS repository of your extension and notify the Composer repository about the new release. People will then be able to find the new release and install or update the package through the Composer repository." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "In the release of your package, in addition to code files, you should also consider including the following to help other people learn about and use your extension:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/package.md +msgid "A readme file in the package root directory: it describes what your extension does and how to install and use it. We recommend you write it in [Markdown](https://daringfireball.net/projects/markdown/) format and name the file as `README.md`." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/package.md +msgid "A changelog file in the package root directory: it lists what changes are made in each release. The file may be written in Markdown format and named as `CHANGELOG.md`." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/package.md +msgid "An upgrade file in the package root directory: it gives the instructions on how to upgrade from older releases of the extension. The file may be written in Markdown format and named as `UPGRADE.md`." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/package.md +msgid "Tutorials, demos, screenshots, etc.: these are needed if your extension provides many features that can't be fully covered in the readme file." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/structure/package.md +msgid "API documentation: your code should be well-documented to allow other people to more easily read and understand it." +msgstr "" diff --git a/_translations/po/zh-CN/guide_structure_service.md.po b/_translations/po/zh-CN/guide_structure_service.md.po new file mode 100644 index 00000000..81377ac9 --- /dev/null +++ b/_translations/po/zh-CN/guide_structure_service.md.po @@ -0,0 +1,195 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-11-02 16:25+0000\n" +"PO-Revision-Date: 2025-11-02 16:25+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Bullet: '- ' +#: ../../guide/en/start/databases.md ../../guide/en/structure/domain.md +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Repository" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/domain.md ../../guide/en/structure/service.md +#, no-wrap +msgid "Entity" +msgstr "" + +#. type: Title # +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Service components" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "Application may get complicated, so it makes sense to extract focused parts of business logic or infrastructure into service components. They're typically injected into other components or action handlers. It's usually done via autowiring:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "" +"public function actionIndex(CurrentRoute $route, MyService $myService): ResponseInterface\n" +"{\n" +" $id = $route->getArgument('id');\n" +" \n" +" // ...\n" +" $extraData = $myService->getExtraData($id);\n" +" \n" +" // ...\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "Yii3 doesn't technically imply any limitations on how you build services. In general, there's no need to extend from a base class or implement a certain interface:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "" +"final readonly class MyService\n" +"{\n" +" public function __construct(\n" +" private ExtraDataStorage $extraDataStorage\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function getExtraData(string $id): array\n" +" {\n" +" return $this->extraDataStorage->get($id);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "Services either perform a task or return data. They're created once, put into a DI container and then could be used multiple times. Because of that, it's a good idea to keep your services stateless that's both service itself and any of its dependencies shouldn't hold state. You can ensure it by using `readonly` PHP keyword at class level." +msgstr "" + +#. type: Title ## +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Service dependencies and configuration" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "Services should always define all their dependencies on other services via `__construct()`. It both allows you to use a service right away after it's created and serves as an indicator of a service doing too much if there are too many dependencies." +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "After the service is created, it shouldn't be re-configured in runtime." +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "DI container instance usually **shouldn't** be injected as a dependency. Prefer concrete interfaces." +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "In case of complicated or \"heavy\" initialization, try to postpone it until the service method is called." +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "The same is valid for configuration values. They should be provided as a constructor argument. Related values could be grouped together into value objects. For example, database connection usually requires DSN string, username and password. These three could be combined into Dsn class:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "" +"final readonly class Dsn\n" +"{\n" +" public function __construct(\n" +" public string $dsn,\n" +" public string $username,\n" +" public string $password\n" +" )\n" +" {\n" +" if (!$this->isValidDsn($dsn)) {\n" +" throw new \\InvalidArgumentException('DSN provided is not valid.');\n" +" }\n" +" }\n" +" \n" +" private function isValidDsn(string $dsn): bool\n" +" {\n" +" // check DSN validity \n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Service methods" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "Service method usually does something. It could be a simple thing repeated exactly, but usually it depends on the context. For example:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "" +"final readonly class PostPersister\n" +"{\n" +" public function __construct(\n" +" private Storage $db\n" +" )\n" +" {\n" +" }\n" +" \n" +" public function persist(Post $post)\n" +" {\n" +" $this->db->insertOrUpdate('post', $post); \n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "There's a service that is saving posts into permanent storage such as a database. An object allowing communication with a concrete storage is always the same, so it's injected using constructor while the post saved could vary, so it's passed as a method argument." +msgstr "" + +#. type: Title ## +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Is everything a service?" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "Often it makes sense to choose another class type to place your code into. Check:" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "Widget" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "[Middleware](middleware.md)" +msgstr "" diff --git a/_translations/po/zh-CN/guide_tutorial_console-applications.md.po b/_translations/po/zh-CN/guide_tutorial_console-applications.md.po new file mode 100644 index 00000000..67efb8bc --- /dev/null +++ b/_translations/po/zh-CN/guide_tutorial_console-applications.md.po @@ -0,0 +1,140 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 11:19+0500\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: en/concept/autoloading.md en/security/best-practices.md +#: en/structure/domain.md en/tutorial/console-applications.md +#, no-wrap +msgid "References" +msgstr "" + +#. type: Title # +#: en/tutorial/console-applications.md +#, no-wrap +msgid "Console applications" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "Console applications are mainly used to create utility, background processing and maintenance tasks." +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "To get support for console application in your project, get `yiisoft/yii-console` via composer:" +msgstr "" + +#. type: Fenced code block +#: en/tutorial/console-applications.md +#, no-wrap +msgid "composer require yiisoft/yii-console\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "After it's installed, you can access the entry point as" +msgstr "" + +#. type: Fenced code block +#: en/tutorial/console-applications.md +#, no-wrap +msgid "./yii\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "Out of the box only `serve` command is available. It's starting PHP built-in web server to serve the application locally." +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "Commands are executed with `symfony/console`. To create your own console command, you need to define a command:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/console-applications.md +#, no-wrap +msgid "" +"setHelp('This command serves for demo purpose')\n" +" ->addArgument('name', InputArgument::OPTIONAL, 'Name to greet', 'anonymous');\n" +" }\n" +"\n" +" protected function execute(InputInterface $input, OutputInterface $output): int\n" +" {\n" +" $io = new SymfonyStyle($input, $output);\n" +"\n" +" $name = $input->getArgument('name');\n" +" $io->success(\"Hello, $name!\");\n" +" return ExitCode::OK;\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "Now register the command in `config/params.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/console-applications.md +#, no-wrap +msgid "" +"return [\n" +" 'console' => [\n" +" 'commands' => [\n" +" 'demo/hello' => App\\Demo\\HelloCommand::class,\n" +" ],\n" +" ], \n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "After it's done, the command could be executed as" +msgstr "" + +#. type: Fenced code block +#: en/tutorial/console-applications.md +#, no-wrap +msgid "./yii demo:hello Alice\n" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/console-applications.md +msgid "[Symfony Console component guide](https://symfony.com/doc/current/components/console.html)" +msgstr "" diff --git a/_translations/po/zh-CN/guide_tutorial_mailing.md.po b/_translations/po/zh-CN/guide_tutorial_mailing.md.po new file mode 100644 index 00000000..804abb55 --- /dev/null +++ b/_translations/po/zh-CN/guide_tutorial_mailing.md.po @@ -0,0 +1,606 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 11:19+0500\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: en/tutorial/mailing.md +#, no-wrap +msgid "Mailing" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "Yii simplifies the composition and sending of email messages using the [yiisoft/mailer](https://github.com/yiisoft/mailer) package. This package provides content composition functionality and a basic interface for sending emails. By default, the package includes a file mailer that writes email contents into a file instead of sending them. This is particularly useful during the initial stages of application development." +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To send actual emails, you can use the [Symfony Mailer](https://github.com/yiisoft/mailer-symfony) implementation, which is used in the examples below." +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Configuring the Mailer" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The mailer service allows you to create a message instance, populate it with data, and send it. Typically, you get an instance from the DI container as `Yiisoft\\Mailer\\MailerInterface`." +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can also create an instance manually as follows:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"\n" +"use Yiisoft\\Mailer\\Symfony\\Mailer;\n" +"\n" +"/**\n" +" * @var \\Symfony\\Component\\Mailer\\Transport\\TransportInterface $transport\n" +" */\n" +"\n" +"$mailer = new \\Yiisoft\\Mailer\\Symfony\\Mailer(\n" +" $transport,\n" +");\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The `Yiisoft\\Mailer\\MailerInterface` provides two main methods:" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`send()` - Sends the given email message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`sendMultiple()` - Sends many messages at once." +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Creating a Message" +msgstr "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Simple Text Message" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To create a simple message with a text body, use `Yiisoft\\Mailer\\Message`:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" textBody: 'Plain text content'\n" +");\n" +msgstr "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Simple HTML Message" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" htmlBody: 'HTML content'\n" +");\n" +msgstr "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "HTML Message from template" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "For this example, we will use package rendering package [view](https://github.com/yiisoft/view)." +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" */\n" +"\n" +"$content = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" +msgstr "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Using Layouts" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can also pass parameters to layouts from your template message:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" * @var array $layoutParameters\n" +" */\n" +"\n" +"$messageBody = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$layoutParameters['content'] = $messageBody;\n" +"\n" +"$content = $view->render('path/to/layout.php', $layoutParameters);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" +msgstr "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Layout Example" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can wrap the view rendering result in a layout, similar to how layouts work in web applications. This is useful for setting up shared content like CSS styles:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"\n" +"\n" +"\n" +"\n" +" \n" +"\n" +"\n" +"\n" +"= $content ?>\n" +"\n" +"\n" +"\n" +"\n" +"\n" +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Adding More Data" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The `Yiisoft\\Mailer\\MessageInterface` provides several methods to customize your message:" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withCharset()` - Returns a new instance with the specified charset." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withFrom()` - Returns a new instance with the specified sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withTo()` - Returns a new instance with the specified recipient(s) email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withReplyTo()` - Returns a new instance with the specified reply-to address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withCc()` - Returns a new instance with the specified Cc (extra copy receiver) addresses." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withBcc()` - Returns a new instance with the specified Bcc (hidden copy receiver) addresses." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withSubject()` - Returns a new instance with the specified message subject." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withDate()` - Returns a new instance with the specified date when the message was sent." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withPriority()` - Returns a new instance with the specified priority of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withReturnPath()` - Returns a new instance with the specified return-path (the bounce address) of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withSender()` - Returns a new instance with the specified actual sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHtmlBody()` - Returns a new instance with the specified message HTML content." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withTextBody()` - Returns a new instance with the specified message plain text content." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withAddedHeader()` - Returns a new instance with the specified added custom header value." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHeader()` - Returns a new instance with the specified custom header value." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHeaders()` - Returns a new instance with the specified custom header values." +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "These methods are immutable, meaning they return a new instance of the message with the updated data." +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "Note `with` prefix. It indicates that the method is immutable and returns a new instance of the class with the changed data." +msgstr "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Getters" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The following getters are available to retrieve message data:" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getCharset()` - Returns the charset of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getFrom()` - Returns the message sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getTo()` - Returns the message recipient(s) email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getReplyTo()` - Returns the reply-to address of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getCc()` - Returns the Cc (extra copy receiver) addresses of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getBcc()` - Returns the Bcc (hidden copy receiver) addresses of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getSubject()` - Returns the message subject." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getDate()` - Returns the date when the message was sent, or null if it wasn't set." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getPriority()` - Returns the priority of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getReturnPath()` - Returns the return-path (the bounce address) of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getSender()` - Returns the message actual sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getHtmlBody()` - Returns the message HTML body." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getTextBody()` - Returns the message text body." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getHeader()` - Returns all values for the specified header." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`__toString()` - Returns string representation of this message." +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Attaching Files" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can attach files to your message using the `withAttached()` method:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"use Yiisoft\\Mailer\\File;\n" +"\n" +"// Attach a file from the local file system\n" +"$message = $message->withAttached(\n" +" File::fromPath('/path/to/source/file.pdf'),\n" +");\n" +"\n" +"// Create an attachment on-the-fly\n" +"$message = $message->withAttached(\n" +" File::fromContent('Attachment content', 'attach.txt', 'text/plain'),\n" +");\n" +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Embedding Images" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can embed images into the message content using the `withEmbedded()` method. This is particularly useful when composing messages with views:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"$logo = 'path/to/logo';\n" +"$htmlBody = $this->view->render(\n" +" __DIR__ . 'template.php',\n" +" [\n" +" 'content' => $content,\n" +" 'logoCid' => $logo->cid(),\n" +" ],\n" +");\n" +"return new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" htmlBody: $htmlBody,\n" +" embeddings: $logo\n" +" );\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "In your view or layout template, you can reference the embedded image using its CID:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "{{ description|truncate(100) }}
\n" +"\n" +"{# URL generation #}\n" +"Profile\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**Template Inheritance**: Twig supports template inheritance:\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/layout/main.twig**\n" +msgstr "" + +#. type: Fenced code block (twig) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"\n" +"\n" +"\n" +"Welcome to our website!
\n" +"{% endblock %}\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Rendering Twig Templates" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Use Twig templates the same way as PHP templates:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"// In your controller\n" +"public function about(): ResponseInterface\n" +"{\n" +" return $this->viewRenderer->render('about.twig', [\n" +" 'user' => $this->getCurrentUser(),\n" +" 'posts' => $this->getRecentPosts(),\n" +" ]);\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Custom Template Engines" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "You can create custom template engines by implementing the `TemplateRendererInterface`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +" $value) {\n" +" $content = str_replace(\"{{$key}}\", (string) $value, $content);\n" +" }\n" +" \n" +" return $this->parser->parse($content);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Register your custom renderer:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"use Yiisoft\\Container\\Reference;\n" +"\n" +"// In configuration\n" +"'yiisoft/view' => [\n" +" 'renderers' => [\n" +" 'md' => Reference::to(App\\View\\MarkdownRenderer::class),\n" +" ],\n" +"],\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Now you can use `.md` template files:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/content/help.md**\n" +msgstr "" + +#. type: Fenced code block (markdown) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"# Help: {{title}}\n" +"\n" +"Welcome, {{username}}!\n" +"\n" +"This is a Markdown template with **bold** and *italic* text.\n" +"\n" +"- Feature 1\n" +"- Feature 2\n" +"- Feature 3\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Choosing the Right Template Engine" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"**Use PHP templates when:**\n" +"- You need maximum flexibility and performance\n" +"- Your team is comfortable with PHP\n" +"- You want to leverage existing PHP knowledge\n" +"- You need complex logic in templates (though this should be minimized)\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"**Use Twig templates when:**\n" +"- You want stricter separation between logic and presentation\n" +"- You work with designers who prefer cleaner syntax\n" +"- You need automatic escaping and security features\n" +"- You want template inheritance and advanced features\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"**Use custom templates when:**\n" +"- You have specific requirements not met by PHP or Twig\n" +"- You're working with specialized content formats\n" +"- You need integration with external template systems\n" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/guide/views/template-engines.md +msgid "**Keep templates simple**: Move complex logic to controllers or services" +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/views/template-engines.md +msgid "**Always escape output**: Prevent XSS attacks by properly escaping variables" +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/views/template-engines.md +msgid "**Use meaningful names**: Name your templates and variables clearly" +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/guide/views/template-engines.md +msgid "**Organize templates**: Group related templates in subdirectories" +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/guide/views/template-engines.md +msgid "**Document variables**: Always add type hints for better IDE support" +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/guide/views/template-engines.md +msgid "**Avoid business logic**: Keep business logic in models and services" +msgstr "" diff --git a/_translations/po/zh-CN/guide_views_view-injections.md.po b/_translations/po/zh-CN/guide_views_view-injections.md.po new file mode 100644 index 00000000..1e2a108a --- /dev/null +++ b/_translations/po/zh-CN/guide_views_view-injections.md.po @@ -0,0 +1,179 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/guide/concept/configuration.md +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "Configuration" +msgstr "" + +#. type: Title # +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "View injections" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "The view injections are designed to provide a standardized way to pass parameters to the common layer of views in an application. It allows developers to manage the data that will be available across various views, ensuring flexibility and reusability of code." +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "The view injections could be used if you require `yiisoft/yii-view-renderer` package:" +msgstr "" + +#. type: Fenced code block (sh) +#: ../src/guide/views/view-injections.md ../src/guide/views/view.md +#, no-wrap +msgid "composer require yiisoft/yii-view-renderer\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "In config `params.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"...\n" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" Reference::to(ContentViewInjection::class),\n" +" Reference::to(CsrfViewInjection::class),\n" +" Reference::to(LayoutViewInjection::class),\n" +" ],\n" +" ],\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "New injections" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Start by defining a class that will implement the `Yiisoft\\Yii\\View\\Renderer\\CommonParametersInjectionInterface`. This class will be responsible for providing the parameters you want to inject into your view templates and layouts." +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"class MyCustomParametersInjection implements Yiisoft\\Yii\\View\\Renderer\\CommonParametersInjectionInterface\n" +"{\n" +" // Class properties and methods will go here\n" +"\n" +" public function __construct(UserService $userService)\n" +" {\n" +" $this->userService = $userService;\n" +" }\n" +"\n" +" public function getCommonParameters(): array\n" +" {\n" +" return [\n" +" 'siteName' => 'My Awesome Site',\n" +" 'currentYear' => date('Y'),\n" +" 'user' => $this->userService->getCurrentUser(),\n" +" ];\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Add your new Injection to `params.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" ...,\n" +" Reference::to(MyCustomParametersInjection::class),\n" +" ],\n" +" ],\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "Using Separate Injections for Different Layouts" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "If your application has multiple layouts, you can create separate parameter injections for each layout. This approach allows you to tailor the parameters injected into each layout according to its specific needs, enhancing the flexibility and maintainability of your application." +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Create your custom ViewInjection for a specific layout:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"readonly final class CartViewInjection implements CommonParametersInjectionInterface\n" +"{\n" +" public function __construct(private Cart $cart)\n" +" {\n" +" }\n" +"\n" +" public function getCommonParameters(): array\n" +" {\n" +" return [\n" +" 'cart' => $this->cart,\n" +" ];\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Add your new injection to `params.php` under specific layout name. In the following example, it's `@layout/cart`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" ...,\n" +" Reference::to(MyCustomParametersInjection::class),\n" +" DynamicReference::to(static function (ContainerInterface $container) {\n" +" $cart = $container\n" +" ->get(Cart::class);\n" +"\n" +" return new LayoutSpecificInjections(\n" +" '@layout/cart', // layout name for injection\n" +"\n" +" new CartViewInjection($cart)\n" +" );\n" +" }),\n" +" ],\n" +" ],\n" +msgstr "" diff --git a/_translations/po/zh-CN/guide_views_view.md.po b/_translations/po/zh-CN/guide_views_view.md.po new file mode 100644 index 00000000..d4c0b9bb --- /dev/null +++ b/_translations/po/zh-CN/guide_views_view.md.po @@ -0,0 +1,458 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-26 18:18+0000\n" +"PO-Revision-Date: 2025-12-26 18:18+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md +#: ../src/cookbook/sentry-integration.md +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#: ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md +#: ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/views/view.md +#, no-wrap +msgid "Views" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md ../src/guide/views/view.md +#, no-wrap +msgid "" +"\n" +"\n" +"The message is: = Html::encode($message) ?>
\n" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md ../src/guide/views/view.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'message' => $message,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/view.md +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Basic Concepts" +msgstr "" + +#. type: Fenced code block (sh) +#: ../src/guide/views/view-injections.md ../src/guide/views/view.md +#, no-wrap +msgid "composer require yiisoft/yii-view-renderer\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "View is responsible for presenting data to end users. You give it a template with some placeholders and presentation logic and some data. The view is passing data to the template executing template logic. The end result is ready to be passed to end user, be it a browser, a file to download, an email to send or something else." +msgstr "" + +#. type: Fenced code block (mermaid) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"flowchart LR\n" +" A[Data] --> V[View]\n" +" B[Template] --> V\n" +" V --> C[HTML]\n" +" C --> D[Browser]\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "In Yii3 views are typically PHP files that contain presentation logic and HTML markup. The view system provides a flexible way to organize your presentation layer and supports features like layouts and partial views. Instead of using plain PHP templates, you can leverage [one of the template engines such as Twig](template-engines.md)." +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "For basic view functionality, you need the `yiisoft/view` package:" +msgstr "" + +#. type: Fenced code block (sh) +#: ../src/guide/views/view.md +#, no-wrap +msgid "composer require yiisoft/view\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "For web applications, you should also install the `yiisoft/yii-view-renderer` package which provides [PSR-7](https://www.php-fig.org/psr/psr-7/) compatibility and web-specific features:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md ../src/guide/views/widget.md +msgid "These packages are included by default in the `yiisoft/app` application template." +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "A view template file contains presentation logic. In the `yiisoft/app` template, view files are typically stored alongside their controllers (e.g., `src/Web/Echo/Action.php`). Here's a simple view file example, `src/Web/Echo/template.php`:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "Here `$message` is a view data that is passed when you render a template with the help of `ViewRenderer`. For example, `src/Web/Echo/Action.php`:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "First argument of the `render()` method is a path to the template file. In the `yiisoft/app`, template files are typically stored alongside their actions. The result is ready to be rendered to the browser so we return it immediately." +msgstr "" + +#. type: Title ## +#: ../src/guide/views/view.md +#, no-wrap +msgid "Working with layouts" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "Most web applications use a common layout for all pages. In the `yiisoft/app` template, layouts are stored in `src/Web/Shared/Layout/Main/` directory. You can set a default layout in `config/common/params.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"return [\n" +" 'yiisoft/yii-view-renderer' => [\n" +" 'viewPath' => null,\n" +" 'layout' => '@src/Web/Shared/Layout/Main/layout.php',\n" +" ],\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "A typical layout file such as `src/Web/Shared/Layout/Main/layout.php` looks like this:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"register(MainAsset::class);\n" +"\n" +"$this->addCssFiles($assetManager->getCssFiles());\n" +"$this->addCssStrings($assetManager->getCssStrings());\n" +"$this->addJsFiles($assetManager->getJsFiles());\n" +"$this->addJsStrings($assetManager->getJsStrings());\n" +"$this->addJsVars($assetManager->getJsVars());\n" +"\n" +"$this->beginPage()\n" +"?>\n" +"\n" +"locale) ?>\">\n" +"\n" +" charset) ?>\">\n" +" \n" +" get('@baseUrl/favicon.svg') ?>\" type=\"image/svg+xml\">\n" +"= Html::encode($post->getExcerpt()) ?>
\n" +" \n" +"= Html::encode($post->getDescription()) ?>
\n" +"\n" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Short echo" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/019-view-code-style.md +msgid "Short echo is preferred:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "= Html::encode($name) ?>\n" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Class methods" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/019-view-code-style.md +msgid "All class methods used in view files must be public regardless if the view is rendered by the class itself." +msgstr "" diff --git a/_translations/po/zh-CN/internals_020-package-release.md.po b/_translations/po/zh-CN/internals_020-package-release.md.po new file mode 100644 index 00000000..2453b1c3 --- /dev/null +++ b/_translations/po/zh-CN/internals_020-package-release.md.po @@ -0,0 +1,136 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "020 — Package release" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "Criteria" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "No critical issues." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Public API changes aren't likely. Some time passed w/o issues reported that may require API changes." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "All dependencies are stable." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Close to 100% test coverage with, ideally, a 100% MSI score." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "README is alright." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Everything is type-hinted unless special cases." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Psalm analysis passes on at least level 2." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "phpdoc is alright." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Public API is alright." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "Release instruction" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/020-package-release.md +msgid "Release a package via [Yii Development Tool](005-development-tool.md)." +msgstr "" + +#. type: Plain text +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "" +"1. Check that you can sign commits locally (see \n" +"[Signing commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)).\n" +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/en/internals/020-package-release.md +msgid "Pull last changes from the `master` branch:" +msgstr "" + +#. type: Fenced code block (shell) +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "" +"./yii-dev git/checkout master package-name\n" +"./yii-dev git/pull package-name\n" +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/en/internals/020-package-release.md +msgid "Check the package for compliance with the criteria above." +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/en/internals/020-package-release.md +msgid "Run `release/make` command:" +msgstr "" + +#. type: Fenced code block (shell) +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "./yii-dev release/make package-name\n" +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/en/internals/020-package-release.md +msgid "Select the version type (major, minor or path)." +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/en/internals/020-package-release.md +msgid "On the question \"Push commits and tags, and release on GitHub?\" check a diff. If the diff is alright, answer \"yes.\"" +msgstr "" + +#. type: Bullet: '7. ' +#: ../src/en/internals/020-package-release.md +msgid "For major and minor releases, add a record with release notes on [Yii Framework News](https://www.yiiframework.com/news)." +msgstr "" diff --git a/_translations/po/zh-CN/internals_021-changelog-upgrade.md.po b/_translations/po/zh-CN/internals_021-changelog-upgrade.md.po new file mode 100644 index 00000000..477e7d49 --- /dev/null +++ b/_translations/po/zh-CN/internals_021-changelog-upgrade.md.po @@ -0,0 +1,130 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "021 — Changelog and upgrade" +msgstr "" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "For all released packages, we've a detailed changelog and upgrade guide." +msgstr "" + +#. type: Title ## +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "Changelog" +msgstr "" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "Changelog is written for each version released. The file name is `CHANGELOG.md`. The format is the following:" +msgstr "" + +#. type: Fenced code block (markdown) +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "" +"# My package Change Log\n" +"\n" +"## 1.0.2 under development\n" +"\n" +"- no changes in this release.\n" +"\n" +"## 1.0.1 March 23, 2021\n" +"\n" +"- Bug #42: Short description of the change (@author1, @author2)\n" +"\n" +"## 1.0.0 February 02, 2021\n" +"\n" +"- Initial release.\n" +msgstr "" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "There \"My package\" is the name of the package, `1.0.1` is the version released followed by release date. For each version, there are a number of lines listing the changes. \"Bug\" refers to a change type. The following types are used:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "New — New features." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "Chg — General changes." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "Enh — Existing feature enhancements." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "Bug — Bug fixes." +msgstr "" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "In the changelog file lines should be ordered as New, Chg, Enh, Bug." +msgstr "" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "\"#42\" above is the number of issue or pull requests corresponding to the change. \"author1\" is the GitHub nickname of the code author. \"author2\" is an additional author. An author's nickname MUST be prefixed with `@`." +msgstr "" + +#. type: Title ## +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "Upgrade" +msgstr "" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "Upgrade guide is created when there is a new major version that isn't compatible with the previous one. It describes steps necessary to upgrade application code." +msgstr "" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "The file name is `UPGRADE.md`. The format is the following:" +msgstr "" + +#. type: Fenced code block (markdown) +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "" +"# Upgrading Instructions for my package\n" +"\n" +"This file contains the upgrade notes. These notes highlight changes that could break your\n" +"application when you upgrade the package from one version to another.\n" +"\n" +"> **Important!** The following upgrading instructions are cumulative. That is, if you want\n" +"> to upgrade from version A to version C and there is version B between A and C, you need\n" +"> to follow the instructions for both A and B.\n" +"\n" +"## Upgrade from 2.x\n" +"\n" +"- Public method `test()` was removed. Use `perform()` instead.\n" +"\n" +"## Upgrade from 1.x\n" +"\n" +"- Clean up the cache after upgrading. Old cache is not compatible with new code.\n" +msgstr "" diff --git a/_translations/po/zh-CN/internals_022-config-groups.md.po b/_translations/po/zh-CN/internals_022-config-groups.md.po new file mode 100644 index 00000000..750d41f1 --- /dev/null +++ b/_translations/po/zh-CN/internals_022-config-groups.md.po @@ -0,0 +1,244 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md ../src/en/guide/concept/events.md +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Events" +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Parameters" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/003-roadmap.md ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Others" +msgstr "" + +#. type: Title # +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "022 — Config groups" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "This document defines naming convention for the framework groups used with [yiisoft/config](https://github.com/yiisoft/config). Note that this isn't a naming convention for config files. These could be anything and are mapped to group names via `composer.json`." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Config group name postfixes" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"web\" postfix applies to web only that's classic server HTML generation, REST, RPC, etc." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"console\" postfix applies to console" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "If there's no postfix, it's \"common\" and applies to both web and console" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"web\" and \"console\" may override what's defined in \"common\"" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Application config parameters that are used in all configs." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params` — common parameters" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params-web` — web application parameters" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params-console` — console application parameters" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Container" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Configuration for [yiisoft/di](https://github.com/yiisoft/di)." +msgstr "" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Definitions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di` — common container definitions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-web` — web container definitions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-console` — console container definitions" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Providers" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers` — common container providers" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers-web` — web container providers" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers-console` — console container providers" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Delegates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates` — common container delegates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates-web` — web container delegates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates-console` — console container delegates" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Tags" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags` — common container tags" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags-web` — web container tags" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags-console` — console container tags" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Configuration for [yiisoft/yii-event](https://github.com/yiisoft/yii-event)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events` — common events" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events-web` — web events" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events-console` — console events" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Bootstrap" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Application bootstrapping for [yiisoft/yii-runner](https://github.com/yiisoft/yii-runner)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap` — common bootstrap" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap-web` — web bootstrap" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap-console` — console bootstrap" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`routes` — [yiisoft/router](https://github.com/yiisoft/router) routes" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`widgets` — [yiisoft/widget](https://github.com/yiisoft/widget) default widgets configuration" +msgstr "" diff --git a/_translations/po/zh-CN/internals_index.md.po b/_translations/po/zh-CN/internals_index.md.po new file mode 100644 index 00000000..98c8b19e --- /dev/null +++ b/_translations/po/zh-CN/internals_index.md.po @@ -0,0 +1,148 @@ +# Language zh-CN translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:23+0000\n" +"PO-Revision-Date: 2025-12-24 08:23+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh-CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/index.md +#, no-wrap +msgid "Yii Framework Internals" +msgstr "" + +#. type: Plain text +#: ../src/internals/index.md +msgid "This section contains documentation for developers contributing to the Yii framework itself. It covers guidelines, workflows, and best practices for maintaining and developing Yii packages." +msgstr "" + +#. type: Title ## +#: ../src/internals/index.md +#, no-wrap +msgid "Table of Contents" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[000 — Packages](000-packages.md) - Package structure and naming conventions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[001 — Yii goal and values](001-yii-values.md) - Project goals and core values" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[002 — Issue workflow](002-issue-workflow.md) - How to handle issues" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[003 — Roadmap](003-roadmap.md) - Development roadmap and future plans" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[004 — Namespaces](004-namespaces.md) - Namespace conventions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[005 — Yii development tool](005-development-tool.md) - Development tools for Yii packages" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[006 — Git commit messages](006-git-commit-messages.md) - Commit message format" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[007 — Exceptions](007-exceptions.md) - Exception handling guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[008 — Interfaces](008-interfaces.md) - Interface design principles" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[009 — Design Decisions](009-design-decisions.md) - Architectural and design decisions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[010 — Code style](010-code-style.md) - PHP code style guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[011 — Error correction](011-error-correction.md) - Error handling and correction" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[012 — Tests](012-tests.md) - Testing guidelines and practices" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[013 — Code review](013-code-review.md) - Code review process and guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[014 — Documentation](014-docs.md) - Documentation writing guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[015 — PhpStorm metadata and attributes](015-phpstorm.md) - PhpStorm integration" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[016 — Security workflow](016-security-workflow.md) - Security issue handling" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[017 — Tags](017-tags.md) - Git tagging conventions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[018 — Widgets](018-widgets.md) - Widget development guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[019 — View code style](019-view-code-style.md) - Code style for view templates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[020 — Package release](020-package-release.md) - Release process for packages" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[021 — Changelog and upgrade](021-changelog-upgrade.md) - Maintaining changelogs and upgrade notes" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[022 — Config groups](022-config-groups.md) - Configuration group organization" +msgstr "" diff --git a/_translations/po4a-base.conf b/_translations/po4a-base.conf index 4a746522..63e1aa0a 100644 --- a/_translations/po4a-base.conf +++ b/_translations/po4a-base.conf @@ -1,4 +1,4 @@ -[po4a_langs] ru id it es +[po4a_langs] ru id it es zh-CN [po4a_paths] pot/$master.pot $lang:po/$lang/$master.po [options] opt:"--verbose" opt:"--addendum-charset=UTF-8" opt:"--localized-charset=UTF-8" opt:"--master-charset=UTF-8" opt:"--master-language=en_US" opt:"--porefs=file" opt:"--msgmerge-opt='--no-wrap'" opt:"--wrap-po=newlines" diff --git a/_translations/po4a.conf b/_translations/po4a.conf index 56b3328b..8d4f96fe 100644 --- a/_translations/po4a.conf +++ b/_translations/po4a.conf @@ -1,4 +1,4 @@ -[po4a_langs] ru id it es +[po4a_langs] ru id it es zh-CN [po4a_paths] pot/$master.pot $lang:po/$lang/$master.po [options] opt:"--verbose" opt:"--addendum-charset=UTF-8" opt:"--localized-charset=UTF-8" opt:"--master-charset=UTF-8" opt:"--master-language=en_US" opt:"--porefs=file" opt:"--msgmerge-opt='--no-wrap'" opt:"--wrap-po=newlines" diff --git a/src/.vitepress/config.js b/src/.vitepress/config.js index b5267ae4..119c78f9 100644 --- a/src/.vitepress/config.js +++ b/src/.vitepress/config.js @@ -1024,6 +1024,200 @@ export default { {icon: 'telegram', link: 'https://t.me/yii3ru'} ], } + }, + 'zh-CN': { + label: '简体中文', + lang: 'zh-CN', + link: '/zh-CN/', + themeConfig: { + nav: [ + {text: '指南', link: '/zh-CN/guide/'}, + {text: '实用手册', link: '/zh-CN/cookbook/'}, + {text: '内部文档', link: '/zh-CN/internals/'}, + {text: '官网', link: 'https://www.yiiframework.com'} + ], + sidebar: { + '/zh-CN/guide/': [ + { + text: '介绍', + items: [ + {text: '关于 Yii', link: '/zh-CN/guide/intro/what-is-yii'}, + {text: '从版本 2 升级', link: '/zh-CN/guide/intro/upgrade-from-v2'} + ] + }, + { + text: '入门', + items: [ + {text: '前置要求', link: '/zh-CN/guide/start/prerequisites'}, + {text: '创建项目', link: '/zh-CN/guide/start/creating-project'}, + {text: '说声 Hello', link: '/zh-CN/guide/start/hello'}, + {text: '使用表单', link: '/zh-CN/guide/start/forms'}, + {text: '使用数据库', link: '/zh-CN/guide/start/databases'}, + {text: '使用 Gii 生成代码', link: '/zh-CN/guide/start/gii'}, + {text: '展望未来', link: '/zh-CN/guide/start/looking-ahead'}, + {text: '应用程序工作流', link: '/zh-CN/guide/start/workflow'} + ] + }, + { + text: '核心概念', + items: [ + {text: '别名', link: '/zh-CN/guide/concept/aliases'}, + {text: '自动加载', link: '/zh-CN/guide/concept/autoloading'}, + {text: '配置', link: '/zh-CN/guide/concept/configuration'}, + {text: 'DI 容器', link: '/zh-CN/guide/concept/di-container'}, + {text: '事件', link: '/zh-CN/guide/concept/events'}, + {text: '不可变性', link: '/zh-CN/guide/concept/immutability'} + ] + }, + { + text: '应用程序结构', + items: [ + {text: '概述', link: '/zh-CN/guide/structure/overview'}, + {text: '入口脚本', link: '/zh-CN/guide/structure/entry-script'}, + {text: '应用程序', link: '/zh-CN/guide/structure/application'}, + {text: '处理器', link: '/zh-CN/guide/structure/handler'}, + {text: '操作', link: '/zh-CN/guide/structure/action'}, + {text: '中间件', link: '/zh-CN/guide/structure/middleware'}, + {text: '领域', link: '/zh-CN/guide/structure/domain'}, + {text: '服务', link: '/zh-CN/guide/structure/service'}, + {text: '包', link: '/zh-CN/guide/structure/package'} + ] + }, + { + text: '处理请求', + items: [ + {text: '路由', link: '/zh-CN/guide/runtime/routing'}, + {text: '请求', link: '/zh-CN/guide/runtime/request'}, + {text: '响应', link: '/zh-CN/guide/runtime/response'}, + {text: '会话', link: '/zh-CN/guide/runtime/sessions'}, + {text: 'Cookies', link: '/zh-CN/guide/runtime/cookies'}, + {text: '错误处理', link: '/zh-CN/guide/runtime/handling-errors'}, + {text: '日志', link: '/zh-CN/guide/runtime/logging'} + ] + }, + { + text: '安全', + items: [ + {text: '概述', link: '/zh-CN/guide/security/overview'}, + {text: '认证', link: '/zh-CN/guide/security/authentication'}, + {text: '授权', link: '/zh-CN/guide/security/authorization'}, + {text: '使用密码', link: '/zh-CN/guide/security/passwords'}, + {text: '加密', link: '/zh-CN/guide/security/cryptography'}, + {text: '可信请求', link: '/zh-CN/guide/security/trusted-request'}, + {text: '最佳实践', link: '/zh-CN/guide/security/best-practices'} + ] + }, + { + text: '缓存', + items: [ + {text: '概述', link: '/zh-CN/guide/caching/overview'}, + {text: '数据缓存', link: '/zh-CN/guide/caching/data'} + ] + }, + { + text: '使用数据库', + items: [ + {text: '数据库迁移', link: '/zh-CN/guide/databases/db-migrations'} + ] + }, + { + text: '视图', + items: [ + {text: '视图', link: '/zh-CN/guide/views/view'}, + {text: '资源', link: '/zh-CN/guide/views/asset'}, + {text: '脚本、样式和元标签', link: '/zh-CN/guide/views/script-style-meta'}, + {text: '模板引擎', link: '/zh-CN/guide/views/template-engines'}, + {text: '视图注入', link: '/zh-CN/guide/views/view-injections'}, + {text: '小部件', link: '/zh-CN/guide/views/widget'} + ] + }, + { + text: '教程', + items: [ + {text: '控制台应用', link: '/zh-CN/guide/tutorial/console-applications'}, + {text: '邮件发送', link: '/zh-CN/guide/tutorial/mailing'}, + {text: '性能调优', link: '/zh-CN/guide/tutorial/performance-tuning'}, + {text: '使用事件循环', link: '/zh-CN/guide/tutorial/using-with-event-loop'}, + {text: '使用 Yii 与 RoadRunner', link: '/zh-CN/guide/tutorial/using-yii-with-roadrunner'}, + {text: '使用 Yii 与 Swoole', link: '/zh-CN/guide/tutorial/using-yii-with-swoole'} + ] + }, + { + text: '术语表', + link: '/zh-CN/guide/glossary' + } + ], + '/zh-CN/cookbook/': [ + { + text: '实用手册', + items: [ + {text: '前言', link: '/zh-CN/cookbook/preface'}, + {text: '发起 HTTP 请求', link: '/zh-CN/cookbook/making-http-requests'}, + {text: '禁用 CSRF 保护', link: '/zh-CN/cookbook/disabling-csrf-protection'}, + {text: 'Sentry 集成', link: '/zh-CN/cookbook/sentry-integration'} + ] + }, + { + text: '配置 Web 服务器', + collapsed: false, + items: [ + {text: '通用配置', link: '/zh-CN/cookbook/configuring-webservers/general'}, + {text: 'Apache', link: '/zh-CN/cookbook/configuring-webservers/apache'}, + {text: 'Nginx', link: '/zh-CN/cookbook/configuring-webservers/nginx'}, + {text: 'Nginx Unit', link: '/zh-CN/cookbook/configuring-webservers/nginx-unit'}, + {text: 'IIS', link: '/zh-CN/cookbook/configuring-webservers/iis'}, + {text: 'Lighttpd', link: '/zh-CN/cookbook/configuring-webservers/lighttpd'} + ] + }, + { + text: '组织代码', + items: [ + {text: '垂直切片', link: '/zh-CN/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices'} + ] + }, + { + text: '部署', + items: [ + {text: 'Docker Swarm', link: '/zh-CN/cookbook/deployment/docker-swarm'} + ] + } + ], + '/zh-CN/internals/': [ + { + text: '内部文档', + items: [ + {text: '包', link: '/zh-CN/internals/000-packages'}, + {text: 'Yii 价值观', link: '/zh-CN/internals/001-yii-values'}, + {text: '问题工作流', link: '/zh-CN/internals/002-issue-workflow'}, + {text: '路线图', link: '/zh-CN/internals/003-roadmap'}, + {text: '命名空间', link: '/zh-CN/internals/004-namespaces'}, + {text: '开发工具', link: '/zh-CN/internals/005-development-tool'}, + {text: 'Git 提交消息', link: '/zh-CN/internals/006-git-commit-messages'}, + {text: '异常', link: '/zh-CN/internals/007-exceptions'}, + {text: '接口', link: '/zh-CN/internals/008-interfaces'}, + {text: '设计决策', link: '/zh-CN/internals/009-design-decisions'}, + {text: '代码风格', link: '/zh-CN/internals/010-code-style'}, + {text: '错误修正', link: '/zh-CN/internals/011-error-correction'}, + {text: '测试', link: '/zh-CN/internals/012-tests'}, + {text: '代码审查', link: '/zh-CN/internals/013-code-review'}, + {text: '文档', link: '/zh-CN/internals/014-docs'}, + {text: 'PHPStorm', link: '/zh-CN/internals/015-phpstorm'}, + {text: '安全工作流', link: '/zh-CN/internals/016-security-workflow'}, + {text: '标签', link: '/zh-CN/internals/017-tags'}, + {text: '小部件', link: '/zh-CN/internals/018-widgets'}, + {text: '视图代码风格', link: '/zh-CN/internals/019-view-code-style'}, + {text: '包发布', link: '/zh-CN/internals/020-package-release'}, + {text: '变更日志和升级', link: '/zh-CN/internals/021-changelog-upgrade'}, + {text: '配置组', link: '/zh-CN/internals/022-config-groups'} + ] + } + ] + }, + footer: { + message: '基于 BSD-3-Clause 许可证 发布。', + copyright: `Copyright © 2008-${currentYear} Yii` + } + } } } } diff --git a/src/zh-CN/cookbook/configuring-webservers/apache.md b/src/zh-CN/cookbook/configuring-webservers/apache.md new file mode 100644 index 00000000..ec1c81a2 --- /dev/null +++ b/src/zh-CN/cookbook/configuring-webservers/apache.md @@ -0,0 +1,55 @@ +# Configuring web servers: Apache + +Use the following configuration in Apache's `httpd.conf` file or within a +virtual host configuration. Note that you should replace +`path/to/app/public` with the actual path for `app/public`. + +```apache +# Set document root to be "app/public" +DocumentRoot "path/to/app/public" + ++ = Html::encode($page->text) ?> +
+ += Html::a('Edit', $urlGenerator->generate('page/edit', ['slug' => $page->getSlug()])) ?> | + + +post($urlGenerator->generate('page/delete', ['slug' => $page->getSlug()])) + ->csrf($csrf); +?> += $deleteForm->open() ?> + = Html::submitButton('Delete') ?> += $deleteForm->close() ?> +``` + +In this view we have a form that submits a request for page +deletion. Handing it with `GET` is common as well, but it is very +wrong. Since deletion changes data, it needs to be handled by one of the +non-idempotent HTTP methods. We use POST and a form in our example, but it +could be `DELETE` and async request made with JavaScript. The button could +be later styled properly to look similar to the "Edit". + +### Delete a page + +Create `src/Web/Page/DeleteAction.php`: + +```php +pageRepository->deleteBySlug($slug); + + return $this->responseFactory + ->createResponse(Status::SEE_OTHER) + ->withHeader('Location', $this->urlGenerator->generate('page/list')); + } +} +``` + +### Create or update a page + +First of all, we need a form at `src/Web/Page/Form.php`: + +```php +findOneBySlug($slug); + if ($page === null) { + return $this->responseFactory->createResponse(Status::NOT_FOUND); + } + + $form->title = $page->title; + $form->text = $page->text; + } + + $this->formHydrator->populateFromPostAndValidate($form, $request); + + if ($form->isValid()) { + $id = $isNew ? Uuid::uuid7()->toString() : $page->id; + + $page = Page::create( + id: $id, + title: $form->title, + text: $form->text, + updatedAt: new DateTimeImmutable(), + ); + + $pageRepository->save($page); + + return $this->responseFactory + ->createResponse(Status::SEE_OTHER) + ->withHeader( + 'Location', + $this->urlGenerator->generate('page/view', ['slug' => $page->getSlug()]), + ); + } + + return $this->viewRenderer->render(__DIR__ . '/edit', [ + 'form' => $form, + 'isNew' => $isNew, + 'slug' => $slug, + ]); + } +} +``` + +Note that `Uuid::uuid7()->toString()` won't work for MySQL and you'll need bytes instead, `Uuid::uuid7()->getBytes()`. + +In the above we use a special slug in the URL for new pages so the URL looks +like `http://localhost/pages/new`. If the page isn't new, we pre-fill the +form with the data from the database. Similar to how we did in [Working with +forms](forms.md), we handle the form submission. After successful save we +redirect to the page view. + +Now, a template in `src/Web/Page/edit.php`: + +```php +post($urlGenerator->generate('page/edit', ['slug' => $slug])) + ->csrf($csrf); +?> + += $htmlForm->open() ?> + = Field::text($form, 'title')->required() ?> + = Field::textarea($form, 'text')->required() ?> + = Html::submitButton('Save') ?> += $htmlForm->close() ?> +``` + +### Routing + +Adjust `config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + Route::methods([Method::GET, Method::POST], '/say') + ->action(Web\Echo\Action::class) + ->name('echo/say'), + + Group::create('/pages')->routes( + Route::get('') + ->action(Web\Page\ListAction::class) + ->name('page/list'), + Route::get('/{slug}') + ->action(Web\Page\ViewAction::class) + ->name('page/view'), + Route::methods([Method::GET, Method::POST], '/{slug}/edit') + ->action(Web\Page\EditAction::class) + ->name('page/edit'), + Route::post('/{slug}/delete') + ->action(Web\Page\DeleteAction::class) + ->name('page/delete'), + ), + ), +]; +``` + +Note that we've grouped all page-related routes with a group under `/pages` +prefix. That is a convenient way to both not to repeat yourself and add some +extra middleware, such as authentication, to the whole group. + +## Trying it out + +Now try it out by opening `http://localhost/pages` in your browser. + diff --git a/src/zh-CN/guide/start/forms.md b/src/zh-CN/guide/start/forms.md new file mode 100644 index 00000000..1e8e6499 --- /dev/null +++ b/src/zh-CN/guide/start/forms.md @@ -0,0 +1,219 @@ +# Working with forms + +This section continues to improve on "Saying Hello." Instead of using URL, +you will now ask a user for a message via form. + +Through this tutorial, you will learn how to: + +* Create a form model to represent the data entered by a user through a + form. +* Declare rules to validate the data entered. +* Build an HTML form in a view. + +## Installing form package + +To install form package, issue the following command in your application +directory: + +``` +composer require yiisoft/form-model +``` + +For Docker that would be: + +``` +make composer require yiisoft/form-model +``` + +## Creating a form + +The data to be requested from the user will be represented by a `Form` class +as shown below and saved in the file `/src/App/Web/Echo/Form.php`: + +```php + + +Now that you have a form, use it in your action from "[Saying +Hello](hello.md)". + +Here's what you end up with in `/src/Web/Echo/Action.php`: + +```php +formHydrator->populateFromPostAndValidate($form, $request); + + return $this->viewRenderer->render(__DIR__ . '/template', [ + 'form' => $form, + ]); + } +} +``` + +Instead of reading from route, you fill your form from request's POST data +and validate it with the help of `FormHydrator`. Next you pass the form to +the view. + +For the form to function we need to allow both GET to render the form and +POST to send the data. Adjust your route in `config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + Route::methods([Method::GET, Method::POST], '/say') + ->action(Web\Echo\Action::class) + ->name('echo/say'), + ), +]; +``` + +## Adjusting view + +To render a form, you need to change your view, `src/Web/Echo/template.php`: + +```php +post($urlGenerator->generate('echo/say')) + ->csrf($csrf); +?> + += $htmlForm->open() ?> + = Field::text($form, 'message')->required() ?> + = Html::submitButton('Say') ?> += $htmlForm->close() ?> + +isValid()): ?> + Echo said: = Html::encode($form->message) ?> + +``` + +If the form is valid, you display a message. The rest initializes and +renders the form. + +First, you initialize `$htmlForm` with the POST type and the action URL +generated with the help from the URL generator. You can access it as +`$urlGenerator` in all views. You also need to pass the CSRF token to the +form, which is also available in every view as `$csrf` thanks to the view +injections listed in `config/common/params.php`: + +```php +'yiisoft/yii-view-renderer' => [ + 'injections' => [ + Reference::to(CsrfViewInjection::class), + ], +], +``` + +The template renders the CSRF token value as a hidden input to ensure that +the request originates from the form page and not from another website. It +will be submitted along with POST form data. Omitting it would result in +[HTTP response code 422](https://tools.ietf.org/html/rfc4918#section-11.2). + +You use `Field::text()` to output "message" field, so it takes care about +filling the value, escaping it, rendering field label and validation errors. + +Now, in case you submit an empty message, you will get a validation error: +"The message to be echoed must contain at least 2 characters." + +## Trying it Out + +To see how it works, use your browser to access the following URL: + +``` +http://localhost:8080/say +``` + +You will see a page with a form input field and a label that indicates what +data to enter. Also, the form has a "submit" button labeled "Say". If you +click the "submit" button without entering anything, you will see that the +field is required. If you enter a single character, the form displays an +error message next to the problematic input field. + + + +After you enter a valid message and click the "submit" button, the page +echoes the data that you entered. + + + +## Summary + +In this section of the guide, you've learned how to create a form model +class to represent the user data and validate said data. + +You've also learned how to get data from users and how to display data back +in the browser. This is a task that could take you a lot of time when +developing an application, but Yii provides powerful widgets to make this +task easy. + +In the next section, you will learn how to work with databases, which are +needed in nearly every application. diff --git a/src/zh-CN/guide/start/gii.md b/src/zh-CN/guide/start/gii.md new file mode 100644 index 00000000..5c34c4c6 --- /dev/null +++ b/src/zh-CN/guide/start/gii.md @@ -0,0 +1 @@ +# Generating code with Gii diff --git a/src/zh-CN/guide/start/hello.md b/src/zh-CN/guide/start/hello.md new file mode 100644 index 00000000..bc9afce2 --- /dev/null +++ b/src/zh-CN/guide/start/hello.md @@ -0,0 +1,191 @@ +# Saying hello + +This section describes how to create a new "Hello" page in your +application. It's a simple page that will echo back whatever you pass to it +or, if nothing passed, will just say "Hello!". + +To achieve this goal, you will define a route and create [a +handler](../structure/handler.md) that does the job and forms the response. +Then you will improve it to use [view](../views/view.md) for building the +response. + +Through this tutorial, you will learn three things: + +1. How to create a handler to respond to a request. +2. How to map URL to the handler. +3. How to use [view](../views/view.md) to compose the response's content. + +## Creating a handler + +For the "Hello" task, you will create a handler class that reads a `message` +parameter from the request and displays that message back to the user. If +the request doesn't provide a `message` parameter, the action will display +the default "Hello" message. + +Create `src/Web/Echo/Action.php`: + +```php +responseFactory->createResponse(); + $response->getBody()->write('The message is: ' . Html::encode($message)); + return $response; + } +} +``` + +In your example, the `__invoke` method receives the `$message` parameter +that with the help of `RouteArgument` attribute gets the message from +URL. The value defaults to `"Hello!"`. If the request is made to +`/say/Goodbye`, the action assigns the value "Goodbye" to the `$message` +variable. + +The application passes the response through the [middleware +stack](../structure/middleware.md) to the emitter that outputs the response +to the end user. + +## Configuring router + +Now, to map your handler to URL, you need to add a route in +`config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + Route::get('/say[/{message}]') + ->action(Web\Echo\Action::class) + ->name('echo/say'), + ), +]; +``` + +In the above, you map the `/say[/{message}]` pattern to +`\App\Web\Echo\Action`. For a request, the router creates an instance and +calls the `__invoke()` method. The `{message}` part of the pattern writes +anything specified in this place to the `message` request attribute. `[]` +marks this part of the pattern as optional. + +You also give a `echo/say` name to this route to be able to generate URLs +pointing to it. + +## Trying it out + +After creating the action and the view open +`http://localhost/say/Hello+World` in your browser. + +This URL displays a page with "The message is: Hello World". + +If you omit the `message` parameter in the URL, the page displays "The +message is: Hello!". + +## Creating a View Template + +Usually, the task is more complicated than printing out "hello world" and +involves rendering some complex HTML. For this task, it's handy to use view +templates. They're scripts you write to generate a response's body. + +For the "Hello" task, create a `src/Web/Echo/template.php` template that +prints the `message` parameter received from the action method: + +```php + + +The message is: = Html::encode($message) ?>
+``` + +In the above code, the `message` parameter uses HTML encoding before you +print it. You need that because the parameter comes from an end user and is +vulnerable to [cross-site scripting (XSS) +attacks](https://en.wikipedia.org/wiki/Cross-site_scripting) by embedding +malicious JavaScript in the parameter. + +Naturally, you may put more content in the `say` view. The content can +consist of HTML tags, plain text, and even PHP statements. In fact, the view +service executes the `say` view as a PHP script. + +To use the view, you need to change `src/Web/Echo/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template', [ + 'message' => $message, + ]); + } +} +``` + +Now open your browser and check it again. You should see the similar text +but with a layout applied. + +Also, you've separated the part about how it works and part of how it's +presented. In the larger applications, it helps a lot to deal with +complexity. + +## Summary + +In this section, you've touched the handler and template parts of the +typical web application. You created a handler as part of a class to handle +a specific request. You also created a view to compose the response's +content. In this simple example, no data source was involved as the only +data used was the `message` parameter. + +You've also learned about routing in Yii, which acts as the bridge between +user requests and handlers. + +In the next section, you will learn how to fetch data and add a new page +containing an HTML form. diff --git a/src/zh-CN/guide/start/looking-ahead.md b/src/zh-CN/guide/start/looking-ahead.md new file mode 100644 index 00000000..47d7d2fe --- /dev/null +++ b/src/zh-CN/guide/start/looking-ahead.md @@ -0,0 +1,9 @@ +# Looking ahead + +If you've read through the entire "Getting Started" chapter, you have now +created a complete Yii application. In the process, you've learned how to +implement some commonly necessary features, such as getting data from users +via an HTML form, fetching data from a database, and displaying data in a +paginated fashion. You've also learned how to use [Gii](gii.md) to generate +code automatically. Using Gii for code generation turns the bulk of your Web +development process into a task as simple as just filling out some forms. diff --git a/src/zh-CN/guide/start/prerequisites.md b/src/zh-CN/guide/start/prerequisites.md new file mode 100644 index 00000000..adc99e39 --- /dev/null +++ b/src/zh-CN/guide/start/prerequisites.md @@ -0,0 +1,44 @@ +# What do you need to know? + +The Yii learning curve isn't as steep as other PHP frameworks, but still, +there are some things you should learn before starting with Yii. + +## PHP + +Yii is a PHP framework, so make sure you [read and understand language +reference](https://www.php.net/manual/en/langref.php). + +## Object-oriented programming + +You need a basic understanding of object-oriented programming. If you're not +familiar with it, check one of the many tutorials available such as [the one +from +tuts+](https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762). + +When you develop with Yii, you write code in an object-oriented fashion, so +make sure you're familiar with [PHP OOP +support](https://www.php.net/manual/en/language.oop5.php). + +Note that the more complicated your application is, the more advanced OOP +concepts you should learn to successfully manage that complexity. + +## Command line and Composer + +Yii extensively uses the de-facto standard PHP package manager, +[Composer](https://getcomposer.org) so make sure you read and understand its +[guide](https://getcomposer.org/doc/01-basic-usage.md). If you aren't +familiar with using the command line, it's time to start trying. Once you +learn the basics, you'll never want to work without it. + +## HTTP + +Since Yii is a web framework and the web largely uses HTTP, it's a good idea +to [learn more about it](https://developer.mozilla.org/en-US/docs/Web/HTTP). + +## Docker + +The default application template leverages Docker, so we recommend that you +[read and understand the concepts](https://docs.docker.com/get-started/). + +Also, you will benefit from familiarizing yourself with [twelve-factor +app](https://12factor.net/) principles. diff --git a/src/zh-CN/guide/start/workflow.md b/src/zh-CN/guide/start/workflow.md new file mode 100644 index 00000000..8d8c2643 --- /dev/null +++ b/src/zh-CN/guide/start/workflow.md @@ -0,0 +1,122 @@ +# Running applications + +After installing Yii, you have a working Yii application. This section +introduces the application's built-in functionality, how the code is +organized, and how the application handles requests in general. + +Note that unlike the framework itself, after you install a project template, +it's all yours. You're free to add or delete code and overall change it as +you need. + +## Functionality + +The installed application contains only one page, accessible at +`http://localhost/`. It shares a common layout that you can reuse on +further pages. + + + +In addition to the web application, you can access a console script via +`APP_ENV=dev ./yii` or, in case of Docker, `make yii`. Use this script to +run background and maintenance tasks for the application, which the [Console +Application Section](../tutorial/console-applications.md) describes. + + +## Application structure + +The most important directories and files in your application are (assuming +the application's root directory is `app`): + +``` +assets/ Asset bundle source files. +config/ Configuration files. + common/ Common configuration and DI definitions. + console/ Console-specific configuration. + environments/ Environment-specific configuration (dev/test/prod). + web/ Web-specific configuration. +docker/ Docker-specific files. +public/ Files publically accessible from the Internet. + assets/ Published/compiled assets. + index.php Entry script. +runtime/ Files generated during runtime. +src/ Application source code. + Console/ Console commands. + Shared/ Code shared between web and console applications. + Web/ Web-specific code (actions, handlers, layout). + Shared/ Shared web components. + Layout/ Layout components and templates. + Environment.php Environment configuration class. +tests/ A set of Codeception tests for the application. + Console/ Console command tests. + Functional/ Functional tests. + Unit/ Unit tests. + Web/ Web actions tests. +vendor/ Installed Composer packages. +Makefile Config for make command. +yii Console application entry point. +``` + +In general, the files in the application fall into two groups: those under +`app/public` and those under other directories. You can access the former +directly via HTTP (i.e., in a browser), while you shouldn't expose the +latter. + +Each application has an entry script `public/index.php`, the only +web-accessible PHP script in the application. The entry script uses an +[application runner](https://github.com/yiisoft/yii-runner) to create an +instance of an incoming request with the help of one of PSR-7 packages and +passes it to an [application](../structure/application.md) instance. The +application executes a set of middleware sequentially to process the +request. It then passes the result to the emitter, which sends the response +to the browser. + +Depending on the middleware you use, the application may behave +differently. By default, a router uses the requested URL and configuration +to choose a handler and execute it to produce a response. + +You can learn more about the application template from the [yiisoft/app +package +documentation](https://github.com/yiisoft/app/blob/master/README.md). + +## Request Lifecycle + +The following diagram shows how an application handles a request. + +```mermaid +flowchart LR + user[User's client] --> index + index[index.php] --> DI[Initialize Dependency Container] + config[configs] -.-> DI + DI --> RequestFactory[RequestFactory] + RequestFactory -->|Request| app[Application] + app -->|Request| middleware[Middleware] + middleware -->|Request| router[Router] + router -->|Request| action[Action Handler] + action -->|Response| emitter[SapiEmitter] + router -->|Response| emitter + middleware -->|Response| emitter + app -->|Response| emitter + emitter --> user +``` + +1. A user makes a request to the [entry + script](../structure/entry-script.md) `public/index.php`. +2. The entry script with the help of the application runner loads the + container [configuration](../concept/configuration.md) and creates an + [application](../structure/application.md) instance and services + necessary to handle the request. +3. Request factory creates a request object based on a raw request that came + from a user. +4. Application passes a request object through a middleware array + configured. One of these is typically a router. +5. The Router finds out what handler to execute based on request and + configuration. +6. The handler may load some data, possibly from a database. +7. The handler forms a response by using data. Either directly or with the + help of the view package. +8. Emitter receives the response and takes care of sending the response to + the user's browser. diff --git a/src/zh-CN/guide/structure/action.md b/src/zh-CN/guide/structure/action.md new file mode 100644 index 00000000..cc4278ec --- /dev/null +++ b/src/zh-CN/guide/structure/action.md @@ -0,0 +1,118 @@ +# Actions + +In a web application, the request URL determines what's executed. Matching +is made by a router configured with multiple routes. Each route can be +attached to a middleware that, given request, produces a response. Since +middleware overall could be chained and can pass actual handling to the next +middleware, we call the middleware actually doing the job an action. + +There are multiple ways to describe an action. The simplest one is using a +closure: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; +use Yiisoft\Router\Route; + +Route::get('/')->action(function (ServerRequestInterface $request) use ($responseFactory): ResponseInterface { + $response = $responseFactory->createResponse(); + $response->getBody()->write('You are at homepage.'); + return $response; +}); +``` + +It's fine for simple handling since any more complicated one would require +getting dependencies, so a good idea would be moving the handling to a class +method. Callback middleware could be used for the purpose: + +```php +use Yiisoft\Router\Route; + +Route::get('/')->action(FrontPageAction::class), +``` + +The class itself would be like: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; + +final readonly class FrontPageAction +{ + public function __invoke(ServerRequestInterface $request): ResponseInterface + { + // build response for a front page + } +} +``` + +For many cases, it makes sense to group handling for many routes into a +single class: + + +```php +use Yiisoft\Router\Route; + +Route::get('/post/index')->action([PostController::class, 'actionIndex']), +Route::get('/post/view/{id:\d+}')->action([PostController::class, 'actionView']), +``` + +The class itself would look like the following: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; + +final readonly class PostController +{ + public function actionIndex(ServerRequestInterface $request): ResponseInterface + { + // render posts list + } + + + public function actionView(ServerRequestInterface $request): ResponseInterface + { + // render a single post + } +} +``` + +We usually call such a class "controller." + +## Autowiring + +Both constructors of action-classes and action-methods are automatically getting services from + the dependency injection container: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; +use Psr\Log\LoggerInterface; + +final readonly class PostController +{ + public function __construct( + private PostRepository $postRepository + ) + { + } + + public function actionIndex(ServerRequestInterface $request, LoggerInterface $logger): ResponseInterface + { + $logger->debug('Rendering posts list'); + // render posts list + } + + + public function actionView(ServerRequestInterface $request): ResponseInterface + { + // render a single post + } +} +``` + +In the above example `PostRepository` is injected automatically via +constructor. That means it is available in every action. Logger is injected +into `index` action only. + diff --git a/src/zh-CN/guide/structure/application.md b/src/zh-CN/guide/structure/application.md new file mode 100644 index 00000000..3fff6311 --- /dev/null +++ b/src/zh-CN/guide/structure/application.md @@ -0,0 +1,18 @@ +# Application + +The primary purpose of the web application and its runner in Yii3 is to +process requests to get responses. + +Typically, the runtime consists of: + +1. Startup. Get config, create an instance of container and do additional + environment initialization such as registering error handler, so it can + handle errors occurring. Fire `ApplicationStartup` event. +2. Handle requests via passing request objects to middleware dispatcher to + execute [middleware stack](middleware.md) and get a response object. In + usual PHP applications, it's done once. In [environments such as + RoadRunner](../tutorial/using-with-event-loop.md), it could be done + multiple times with the same application instance. Response object is + converted into an actual HTTP response by using emitter. Fire + `AfterEmit` event. +3. Shutdown. Fire `ApplicationShutdown` event. diff --git a/src/zh-CN/guide/structure/domain.md b/src/zh-CN/guide/structure/domain.md new file mode 100644 index 00000000..6a35bb14 --- /dev/null +++ b/src/zh-CN/guide/structure/domain.md @@ -0,0 +1,91 @@ +# Domain + +The Domain or domain model is what makes the project unique. With requirements and terminology of the problem being solved +in mind (the problem context), you build an abstraction that consists of entities, their relationships, and logic that +operates these entities. To focus on the complex part of the problem, domain is, ideally, separated from + the infrastructure part of the system (that's how to save data into a database, how to form HTTP response, etc.). + +> [!NOTE] +> Such isolation is suitable for complex systems. If your project domain is basically create/read/update/delete +> for a set of records with not much complex logic, it makes no sense to apply a complex solution to a simple problem. +> The individual concepts of domain design below could be applied separately, so make sure to check these even if your +> project isn't that complicated. + +## Bounded context + +It's nearly impossible to build a model that solves multiple problems that +aren't too complicated by itself. Therefore, it's a good practice to divide +the domain into several use-cases and have a separate model for each +use-case. Such separated models are called "bounded contexts." + +## Building blocks + +There are various building blocks that are typically used when describing +domain models. It isn't mandatory to use them all. + +### Entity + +Entity is a uniquely identifiable object such as user, product, payment, +etc. When comparing them, you're checking ID, not the attribute values. If +there are two objects with different attributes but the same ID, they're +considered being the same thing. + +### Value object + +Value object describes an object by its characteristics. For example, a +price that consists of value and currency. When comparing such objects, +you're checking actual values. If they match, an object is considered to be +the same. + +### Aggregate + +Aggregate is a set of domain objects such as entities and value objects and +additional data that could be treated as a single unit. It usually +represents a compound object from a domain model such as shop order or HR +person dossier. + +One of the components of an aggregate is called a root. The root identifies +an aggregate as a whole and should be used to access it. + +### Domain event + +An aggregate, while processed, may raise events. For example, when order is +confirmed, `OrderConfirmed` event would be risen so other parts of the +system may react on these. + +### Data transfer object + +Data transfer object or DTO is an object whose only purpose is to hold data +as it is. It's commonly used to pass data between different services. + +### Service + +Service is a class that contains a standalone operation within the context +of your domain model. See "[service components](service.md)". + +### Repository + +The repository task is to abstract away how domain objects are +obtained. These are usually separated into two parts: an interface that +stays in the domain layer and an implementation that's situated in the +infrastructure layer. In such a way, domain doesn't care how data is +obtained and saved and may be focused around the complicated business logic +instead. + +Repository is usually implemented as a service. + +### Instantiating building blocks + +Entity, value object, aggregate, and domain events aren't services and +shouldn't be instantiated through DI container. Using `new` is the way to +go with these. + +## References + +- [BoundedContext by Martin + Fowler](https://martinfowler.com/bliki/BoundedContext.html) +- [ValueObject by Martin + Fowler](https://martinfowler.com/bliki/ValueObject.html) +- [Aggregate by Marting + Fowler](https://martinfowler.com/bliki/DDD_Aggregate.html) + diff --git a/src/zh-CN/guide/structure/entry-script.md b/src/zh-CN/guide/structure/entry-script.md new file mode 100644 index 00000000..29f63c0f --- /dev/null +++ b/src/zh-CN/guide/structure/entry-script.md @@ -0,0 +1,114 @@ +# Entry scripts + +Entry scripts are the first step in the application bootstrapping +process. An application (either Web application or console application) has +a single entry script. End users make requests to entry scripts which +instantiate application instances and forward the requests to them. + +Entry scripts for Web applications must be stored under Web-accessible +directories so that they can be accessed by end users. They're often named +as `index.php`, but can also use any other names, provided Web servers can +locate them. + +Entry script for console application is `./yii`. + +Entry scripts mainly perform the following work with the help of +`ApplicationRunner`: + +* Register [Composer + autoloader](https://getcomposer.org/doc/01-basic-usage.md#autoloading); +* Obtain configuration; +* Use configuration to initialize a dependency injection container; +* Get an instance of the request. +* Pass it to `Application` to handle and get a response from it. +* With the help of an emitter that transforms a response object into an + actual HTTP response that's sent to the client browser. + +## Web Applications + +The following is the code in the entry script for the application template: + +```php +debug(); +// Run application: +$runner->run(); +``` + + +## Console Applications + +Similarly, the following is the code for the entry script of a console +application: + +```php +#!/usr/bin/env php +withDefinitions($config->get('console')) + ->withProviders($config->get('providers-console')); +$container = new Container($containerConfig); + +/** @var ContainerInterface $container */ +$container = $container->get(ContainerInterface::class); + +$application = $container->get(Application::class); +$exitCode = 1; + +try { + $application->start(); + $exitCode = $application->run(null, new ConsoleBufferedOutput()); +} catch (\Error $error) { + $application->renderThrowable($error, new ConsoleBufferedOutput()); +} finally { + $application->shutdown($exitCode); + exit($exitCode); +} +``` + +## Alternative runtimes + +For alternative runtimes such as RoadRunner or Swoole, special entry scripts +should be used. See: + +- [Using Yii with RoadRunner](../tutorial/using-yii-with-roadrunner.md) +- [Using Yii with Swoole](../tutorial/using-yii-with-swoole.md) diff --git a/src/zh-CN/guide/structure/middleware.md b/src/zh-CN/guide/structure/middleware.md new file mode 100644 index 00000000..2b450c2c --- /dev/null +++ b/src/zh-CN/guide/structure/middleware.md @@ -0,0 +1,195 @@ +# Middleware + +Yii works with HTTP using the abstraction layer built around [PSR-7 HTTP +message interfaces](https://www.php-fig.org/psr/psr-7/) and [PSR-15 request +handler/middleware interfaces](https://www.php-fig.org/psr/psr-15/). + +The application is composed of one or several middleware. Middleware runs +between request and response. When the URL is requested, the request object +is passed to the middleware dispatcher that starts executing middleware one +after another. Each middleware, given the request, can: + +- Pass the request to the next middleware performing some work before / + after it. +- Form the response and return it. + +Depending on middleware used, application behavior may vary significantly. + + + +In the above each next middleware wraps the previous +middleware. Alternatively, it could be presented as follows: + + + +## Using middleware + +Any [PSR-15](https://www.php-fig.org/psr/psr-15/) compatible middleware +could be used with Yii, and there are many. Say, you need to add basic +authentication to one of the application URLs. URL-dependent middleware is +configured using router, so you need to change the router factory. + +Authentication middleware is implemented by +`middlewares/http-authentication` package so execute `composer require +middlewares/http-authentication` in the application root directory. + +Now register the middleware in DI container configuration `config/web.php`: + +```php + [ + 'class' => \Middlewares\BasicAuthentication::class, + '__construct()' => [ + 'users' => [ + 'foo' => 'bar', + ], + ], + 'realm()' => ['Access to the staging site via basic auth'], + 'attribute()' => ['username'], +], +``` + +In the `config/routes.php`, add new route: + +```php +action([SiteController::class, 'auth']) + ->name('site/auth') + ->prependMiddleware(BasicAuthentication::class) +]; +``` + +When configuring routing, you're binding `/basic-auth` URL to a chain of +middleware consisting of basic authentication, and the action itself. A +chain is a special middleware that executes all the middleware it's +configured with. + +The action itself could be the following: + +```php +public function auth(ServerRequestInterface $request): ResponseInterface +{ + $response = $this->responseFactory->createResponse(); + $response->getBody()->write('Hi ' . $request->getAttribute('username')); + return $response; +} +``` + +Basic authentication middleware wrote to request `username` attribute, so +you can access the data if needed. + +To apply middleware to application overall regardless of URL, adjust +`config/application.php`: + +```php +return [ + Yiisoft\Yii\Http\Application::class => [ + '__construct()' => [ + 'dispatcher' => DynamicReference::to(static function (Injector $injector) { + return ($injector->make(MiddlewareDispatcher::class)) + ->withMiddlewares( + [ + ErrorCatcher::class, + BasicAuthentication::class, + SessionMiddleware::class, + CsrfMiddleware::class, + Router::class, + ] + ); + }), + 'fallbackHandler' => Reference::to(NotFoundHandler::class), + ], + ], +]; +``` + +## Creating your own middleware + +To create middleware, you need to implement a single `process` method of +`Psr\Http\Server\MiddlewareInterface`: + +```php +public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface; +``` + +There are multiple ways to handle a request, and choosing one depends on +what the middleware should achieve. + +### Forming a response directly + +To respond directly, one needs a response factory passed via constructor: + +```php +responseFactory->createResponse(); + $response->getBody()->write('Hello!'); + return $response; + } +} +``` + +### Delegating handling to the next middleware + +If middleware either isn't intended to form a response or change the request or can't do anything this time, +handling could be left to the next middleware in the stack: + +```php +public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface +{ + return $handler->handle($request); +} +``` + +In case you need to pass data to the next middleware, you can use request +attributes: + +```php +$request = $request->withAttribute('answer', 42); +return $handler->handle($request); +``` + +To get it in the next middleware: + +```php +$answer = $request->getAttribute('answer'); +``` + +### Capturing response to manipulate it + +You may want to capture the response to manipulate it. It could be useful +for adding CORS headers, gzipping content, etc. + +```php +$response = $handler->handle($request); +// extra handing +return $response; +``` diff --git a/src/zh-CN/guide/structure/overview.md b/src/zh-CN/guide/structure/overview.md new file mode 100644 index 00000000..3d8f5d9d --- /dev/null +++ b/src/zh-CN/guide/structure/overview.md @@ -0,0 +1,65 @@ +# Overview + +Yii applications code is typically grouped into modules by context. In each +module there could be grouping by type. + +For example, if the application is an online store, the context could be: + +- Customer + - Profile + - Products list + - Checkout +- Logistics +- Delivery + - Addresses +- Helpdesk + - Support + - Claims + - Returns +- Accounting + - Returns + - Transactions + - Taxes + +For a "Customer" context, residing under `App\Customer` namespace, structure +would be: + +``` +App/ + Customer/ <-- module namespace + Entity/ + Customer.php <-- entity shared by "Profile" and "Checkout" + Profile/ + Widget/ + Gravatar.php + ProfileRepository.php <-- repository is usually specific to context + ProfileController.php <-- "Customer\Profile" entry point + ProductList/ <-- module namespace + Entity/ <-- entities specific to "Customer\ProductList" + Category.php + Product.php + ProductsListController.php <-- "Customer\ProductList" entry point + Checkout/ <-- module namespace + CheckoutController.php +``` + +A context may include sub-contexts. If a class is shared by multiple +contexts, it's moved to the ancestor of both contexts. + +A context may have [an entry point known as "action" or +"controller"](action.md). Its job is to take [a request +instance](../runtime/request.md), pass it to [domain layer](domain.md) in a +suitable format, and create [a response](../runtime/response.md) based on +domain layer return. + +Besides, Yii applications also have the following: + +* [entry scripts](entry-script.md): they're PHP scripts that are directly + accessible by end users. They're responsible for starting a request + handling cycle. Typically, a single entry script is handling the whole + application. +* [services](service.md): they're typically stateless objects registered + within dependency container and provide various action methods. +* [middleware](middleware.md): they represent a code that needs to be + invoked before and after the actual handling of each request by action + handlers. diff --git a/src/zh-CN/guide/structure/package.md b/src/zh-CN/guide/structure/package.md new file mode 100644 index 00000000..a0bb1716 --- /dev/null +++ b/src/zh-CN/guide/structure/package.md @@ -0,0 +1,242 @@ +# Packages + +Reusable code could be released as [a Composer +package](https://getcomposer.org/doc/05-repositories.md#package). It could +be an infrastructure library, a module representing one of the application +contexts or, basically, any reusable code. + +## Using packages + +By default, Composer installs packages registered on +[Packagist](https://packagist.org/) — the biggest repository for open source +PHP packages. You can look for packages on Packagist. You may also [create +your own +repository](https://getcomposer.org/doc/05-repositories.md#repository) and +configure Composer to use it. This is useful if you're developing private +packages that you want to share within your projects only. + +Packages installed by Composer are stored in the `vendor` directory of your +project. Because the Composer is a dependency manager, when it installs a +package, it will also install all its dependent packages. + +> [!WARNING] +> `vendor` directory of your application should never be modified. + +A package could be installed with the following command: + +``` +composer install vendor-name/package-name +``` + +After it's done, Composer modifies `composer.json` and `composer.lock`. The +former defines what packages to install, and their version constraints the +latter stores a snapshot of exact versions actually installed. + +Classes from the package will be available immediately via +[autoloading](../concept/autoloading.md). + +## Creating packages + + +You may consider creating a package when you feel the need to share with +other people your great code. A package can contain any code you like, such +as a helper class, a widget, a service, middleware, the whole module, etc. + +Below are the basic steps you may follow. + +1. Create a project for your package and host it on a VCS repository, such + as [GitHub.com](https://github.com). The development and maintenance + work for the package should be done on this repository. +2. Under the root directory of the project, create a file named + `composer.json` as required by Composer. Please refer to the next + subsection for more details. +3. Register your package with a Composer repository, such as + [Packagist](https://packagist.org/), so that other users can find and + install your package using Composer. + + +### `composer.json` + +Each Composer package must have a `composer.json` file in its root +directory. The file contains the metadata about the package. You may find +the complete specification about this file in the [Composer +Manual](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup). +The following example shows the `composer.json` file for the +`yiisoft/yii-widgets` package: + +```json +{ + "name": "yiisoft/yii-widgets", + "type": "library", + "description": "Yii widgets collection", + "keywords": [ + "yii", + "widgets" + ], + "homepage": "https://www.yiiframework.com/", + "license": "BSD-3-Clause", + "support": { + "issues": "https://github.com/yiisoft/yii-widgets/issues?state=open", + "forum": "https://www.yiiframework.com/forum/", + "wiki": "https://www.yiiframework.com/wiki/", + "irc": "ircs://irc.libera.chat:6697/yii", + "chat": "https://t.me/yii3en", + "source": "https://github.com/yiisoft/yii-widgets" + }, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/yiisoft" + }, + { + "type": "github", + "url": "https://github.com/sponsors/yiisoft" + } + ], + "require": { + "php": "^7.4|^8.0", + "yiisoft/aliases": "^1.1|^2.0", + "yiisoft/cache": "^1.0", + "yiisoft/html": "^2.0", + "yiisoft/view": "^4.0", + "yiisoft/widget": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "roave/infection-static-analysis-plugin": "^1.16", + "spatie/phpunit-watcher": "^1.23", + "vimeo/psalm": "^4.18", + "yiisoft/psr-dummy-provider": "^1.0", + "yiisoft/test-support": "^1.3" + }, + "autoload": { + "psr-4": { + "Yiisoft\\Yii\\Widgets\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Yiisoft\\Yii\\Widgets\\Tests\\": "tests" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "scripts": { + "test": "phpunit --testdox --no-interaction", + "test-watch": "phpunit-watcher watch" + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "infection/extension-installer": true, + "composer/package-versions-deprecated": true + } + } +} +``` + + +#### Package Name + +Each Composer package should have a package name which uniquely identifies +the package among all others. The format of package names is +`vendorName/projectName`. For example, in the package name `yiisoft/queue`, +the vendor name, and the project name are `yiisoft` and `queue`, +respectively. + +> [!WARNING] +> Don't use `yiisoft` as your vendor name as it's reserved for use by the Yii itself. + +We recommend you prefix `yii-` to the project name for packages that aren't +able to work as general PHP packages and require Yii application. This will +allow users to more easily tell whether a package is Yii specific. + + +#### Dependencies + +If your extension depends on other packages, you should list them in +`require` section of `composer.json`. Make sure you also list appropriate +version constraints (e.g. `^1.0`, `@stable`) for each dependent package. +Use stable dependencies when your extension is released in a stable version. + +#### Class Autoloading + +In order for your classes to be autoloaded, you should specify the +`autoload` entry in the `composer.json` file, like shown below: + +```json +{ + // .... + + "autoload": { + "psr-4": { + "MyVendorName\\MyPackageName\\": "src" + } + } +} +``` + +You may list one or multiple root namespaces and their corresponding file +paths. + +### Recommended Practices + +Because packages are meant to be used by other people, you often need to +make an extra effort during development. Below, we introduce some common +and recommended practices in creating high-quality extensions. + + +#### Testing + +You want your package to run flawlessly without bringing problems to other +people. To reach this goal, you should test your extension before releasing +it to the public. + +It's recommended that you create various test cases to cover your extension +code rather than relying on manual tests. Each time before you release a +new version of your package, you may run these test cases to make sure +everything is in good shape. For more details, please refer to the +[Testing](../testing/overview.md) section. + + +#### Versioning + +You should give each release of your extension a version number +(e.g. `1.0.1`). We recommend you follow the [semantic +versioning](https://semver.org) practice when determining what version +numbers should be used. + + +#### Releasing + +To let other people know about your package, you need to release it to the +public. + +If it's the first time you're releasing a package, you should register it in +a Composer repository, such as [Packagist](https://packagist.org/). After +that, all you need to do is create a release tag (for example, `v1.0.1`) on +the VCS repository of your extension and notify the Composer repository +about the new release. People will then be able to find the new release and +install or update the package through the Composer repository. + +In the release of your package, in addition to code files, you should also +consider including the following to help other people learn about and use +your extension: + +* A readme file in the package root directory: it describes what your + extension does and how to install and use it. We recommend you write it + in [Markdown](https://daringfireball.net/projects/markdown/) format and + name the file as `README.md`. +* A changelog file in the package root directory: it lists what changes are + made in each release. The file may be written in Markdown format and named + as `CHANGELOG.md`. +* An upgrade file in the package root directory: it gives the instructions + on how to upgrade from older releases of the extension. The file may be + written in Markdown format and named as `UPGRADE.md`. +* Tutorials, demos, screenshots, etc.: these are needed if your extension + provides many features that can't be fully covered in the readme file. +* API documentation: your code should be well-documented to allow other + people to more easily read and understand it. diff --git a/src/zh-CN/guide/structure/service.md b/src/zh-CN/guide/structure/service.md new file mode 100644 index 00000000..0baee5d5 --- /dev/null +++ b/src/zh-CN/guide/structure/service.md @@ -0,0 +1,119 @@ +# Service components + +Application may get complicated, so it makes sense to extract focused parts +of business logic or infrastructure into service components. They're +typically injected into other components or action handlers. It's usually +done via autowiring: + +```php +public function actionIndex(CurrentRoute $route, MyService $myService): ResponseInterface +{ + $id = $route->getArgument('id'); + + // ... + $extraData = $myService->getExtraData($id); + + // ... +} +``` + +Yii3 doesn't technically imply any limitations on how you build services. In +general, there's no need to extend from a base class or implement a certain +interface: + +```php +final readonly class MyService +{ + public function __construct( + private ExtraDataStorage $extraDataStorage + ) + { + } + + public function getExtraData(string $id): array + { + return $this->extraDataStorage->get($id); + } +} +``` + +Services either perform a task or return data. They're created once, put +into a DI container and then could be used multiple times. Because of that, +it's a good idea to keep your services stateless that's both service itself +and any of its dependencies shouldn't hold state. You can ensure it by using +`readonly` PHP keyword at class level. + +## Service dependencies and configuration + +Services should always define all their dependencies on other services via +`__construct()`. It both allows you to use a service right away after it's +created and serves as an indicator of a service doing too much if there are +too many dependencies. + +- After the service is created, it shouldn't be re-configured in runtime. +- DI container instance usually **shouldn't** be injected as a + dependency. Prefer concrete interfaces. +- In case of complicated or "heavy" initialization, try to postpone it until + the service method is called. + +The same is valid for configuration values. They should be provided as a +constructor argument. Related values could be grouped together into value +objects. For example, database connection usually requires DSN string, +username and password. These three could be combined into Dsn class: + +```php +final readonly class Dsn +{ + public function __construct( + public string $dsn, + public string $username, + public string $password + ) + { + if (!$this->isValidDsn($dsn)) { + throw new \InvalidArgumentException('DSN provided is not valid.'); + } + } + + private function isValidDsn(string $dsn): bool + { + // check DSN validity + } +} +``` + +## Service methods + +Service method usually does something. It could be a simple thing repeated +exactly, but usually it depends on the context. For example: + +```php +final readonly class PostPersister +{ + public function __construct( + private Storage $db + ) + { + } + + public function persist(Post $post) + { + $this->db->insertOrUpdate('post', $post); + } +} +``` + +There's a service that is saving posts into permanent storage such as a +database. An object allowing communication with a concrete storage is always +the same, so it's injected using constructor while the post saved could +vary, so it's passed as a method argument. + +## Is everything a service? + +Often it makes sense to choose another class type to place your code +into. Check: + +- Repository +- Widget +- [Middleware](middleware.md) +- Entity diff --git a/src/zh-CN/guide/tutorial/console-applications.md b/src/zh-CN/guide/tutorial/console-applications.md new file mode 100644 index 00000000..3f5d2e11 --- /dev/null +++ b/src/zh-CN/guide/tutorial/console-applications.md @@ -0,0 +1,85 @@ +# Console applications + +Console applications are mainly used to create utility, background +processing and maintenance tasks. + +To get support for console application in your project, get +`yiisoft/yii-console` via composer: + + +``` +composer require yiisoft/yii-console +``` + +After it's installed, you can access the entry point as + +``` +./yii +``` + +Out of the box only `serve` command is available. It's starting PHP built-in +web server to serve the application locally. + +Commands are executed with `symfony/console`. To create your own console +command, you need to define a command: + +```php +setHelp('This command serves for demo purpose') + ->addArgument('name', InputArgument::OPTIONAL, 'Name to greet', 'anonymous'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $name = $input->getArgument('name'); + $io->success("Hello, $name!"); + return ExitCode::OK; + } +} +``` + +Now register the command in `config/params.php`: + +```php +return [ + 'console' => [ + 'commands' => [ + 'demo/hello' => App\Demo\HelloCommand::class, + ], + ], +]; +``` + +After it's done, the command could be executed as + +``` +./yii demo:hello Alice +``` + + +## References + +- [Symfony Console component + guide](https://symfony.com/doc/current/components/console.html) diff --git a/src/zh-CN/guide/tutorial/mailing.md b/src/zh-CN/guide/tutorial/mailing.md new file mode 100644 index 00000000..e5833e5d --- /dev/null +++ b/src/zh-CN/guide/tutorial/mailing.md @@ -0,0 +1,329 @@ +# Mailing + +Yii simplifies the composition and sending of email messages using the +[yiisoft/mailer](https://github.com/yiisoft/mailer) package. This package +provides content composition functionality and a basic interface for sending +emails. By default, the package includes a file mailer that writes email +contents into a file instead of sending them. This is particularly useful +during the initial stages of application development. + +To send actual emails, you can use the [Symfony +Mailer](https://github.com/yiisoft/mailer-symfony) implementation, which is +used in the examples below. + +## Configuring the Mailer + +The mailer service allows you to create a message instance, populate it with +data, and send it. Typically, you get an instance from the DI container as +`Yiisoft\Mailer\MailerInterface`. + +You can also create an instance manually as follows: + +```php + +use Yiisoft\Mailer\Symfony\Mailer; + +/** + * @var \Symfony\Component\Mailer\Transport\TransportInterface $transport + */ + +$mailer = new \Yiisoft\Mailer\Symfony\Mailer( + $transport, +); +``` + +The `Yiisoft\Mailer\MailerInterface` provides two main methods: + +- `send()` - Sends the given email message. +- `sendMultiple()` - Sends many messages at once. + +## Creating a Message + +### Simple Text Message + +To create a simple message with a text body, use `Yiisoft\Mailer\Message`: + +```php +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Message subject', + textBody: 'Plain text content' +); +``` + +### Simple HTML Message + +```php +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Message subject', + htmlBody: 'HTML content' +); +``` + +### HTML Message from template + +For this example, we will use package rendering package +[view](https://github.com/yiisoft/view). + +```php +/** + * @var \Yiisoft\View\View $view + */ + +$content = $view->render('path/to/view.php', [ + 'name' => 'name', + 'code' => 'code', +]); + +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Subject', + htmlBody: $content +); +``` + +### Using Layouts + +You can also pass parameters to layouts from your template message: + +```php +/** + * @var \Yiisoft\View\View $view + * @var array $layoutParameters + */ + +$messageBody = $view->render('path/to/view.php', [ + 'name' => 'name', + 'code' => 'code', +]); + +$layoutParameters['content'] = $messageBody; + +$content = $view->render('path/to/layout.php', $layoutParameters); + +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Subject', + htmlBody: $content +); +``` + +### Layout Example + +You can wrap the view rendering result in a layout, similar to how layouts +work in web applications. This is useful for setting up shared content like +CSS styles: + +```php + + + + + + + + += $content ?> + + + + + +``` + +## Adding More Data + +The `Yiisoft\Mailer\MessageInterface` provides several methods to customize +your message: + +- `withCharset()` - Returns a new instance with the specified charset. +- `withFrom()` - Returns a new instance with the specified sender email + address. +- `withTo()` - Returns a new instance with the specified recipient(s) email + address. +- `withReplyTo()` - Returns a new instance with the specified reply-to + address. +- `withCc()` - Returns a new instance with the specified Cc (extra copy + receiver) addresses. +- `withBcc()` - Returns a new instance with the specified Bcc (hidden copy + receiver) addresses. +- `withSubject()` - Returns a new instance with the specified message + subject. +- `withDate()` - Returns a new instance with the specified date when the + message was sent. +- `withPriority()` - Returns a new instance with the specified priority of + this message. +- `withReturnPath()` - Returns a new instance with the specified return-path + (the bounce address) of this message. +- `withSender()` - Returns a new instance with the specified actual sender + email address. +- `withHtmlBody()` - Returns a new instance with the specified message HTML + content. +- `withTextBody()` - Returns a new instance with the specified message plain + text content. +- `withAddedHeader()` - Returns a new instance with the specified added + custom header value. +- `withHeader()` - Returns a new instance with the specified custom header + value. +- `withHeaders()` - Returns a new instance with the specified custom header + values. + +These methods are immutable, meaning they return a new instance of the +message with the updated data. + +Note `with` prefix. It indicates that the method is immutable and returns a +new instance of the class with the changed data. + +### Getters + +The following getters are available to retrieve message data: + +- `getCharset()` - Returns the charset of this message. +- `getFrom()` - Returns the message sender email address. +- `getTo()` - Returns the message recipient(s) email address. +- `getReplyTo()` - Returns the reply-to address of this message. +- `getCc()` - Returns the Cc (extra copy receiver) addresses of this + message. +- `getBcc()` - Returns the Bcc (hidden copy receiver) addresses of this + message. +- `getSubject()` - Returns the message subject. +- `getDate()` - Returns the date when the message was sent, or null if it + wasn't set. +- `getPriority()` - Returns the priority of this message. +- `getReturnPath()` - Returns the return-path (the bounce address) of this + message. +- `getSender()` - Returns the message actual sender email address. +- `getHtmlBody()` - Returns the message HTML body. +- `getTextBody()` - Returns the message text body. +- `getHeader()` - Returns all values for the specified header. +- `__toString()` - Returns string representation of this message. + +## Attaching Files + +You can attach files to your message using the `withAttached()` method: + +```php +use Yiisoft\Mailer\File; + +// Attach a file from the local file system +$message = $message->withAttached( + File::fromPath('/path/to/source/file.pdf'), +); + +// Create an attachment on-the-fly +$message = $message->withAttached( + File::fromContent('Attachment content', 'attach.txt', 'text/plain'), +); +``` + +## Embedding Images + +You can embed images into the message content using the `withEmbedded()` +method. This is particularly useful when composing messages with views: + +```php +$logo = 'path/to/logo'; +$htmlBody = $this->view->render( + __DIR__ . 'template.php', + [ + 'content' => $content, + 'logoCid' => $logo->cid(), + ], +); +return new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Message subject', + htmlBody: $htmlBody, + embeddings: $logo + ); +``` + +In your view or layout template, you can reference the embedded image using +its CID: + +```php +{{ description|truncate(100) }}
+ +{# URL generation #} +Profile +``` + +**Template Inheritance**: Twig supports template inheritance: + +**views/layout/main.twig** +```twig + + + +Welcome to our website!
+{% endblock %} +``` + +### Rendering Twig Templates + +Use Twig templates the same way as PHP templates: + +```php +// In your controller +public function about(): ResponseInterface +{ + return $this->viewRenderer->render('about.twig', [ + 'user' => $this->getCurrentUser(), + 'posts' => $this->getRecentPosts(), + ]); +} +``` + +## Custom Template Engines + +You can create custom template engines by implementing the +`TemplateRendererInterface`: + +```php + $value) { + $content = str_replace("{{$key}}", (string) $value, $content); + } + + return $this->parser->parse($content); + } +} +``` + +Register your custom renderer: + +```php +use Yiisoft\Container\Reference; + +// In configuration +'yiisoft/view' => [ + 'renderers' => [ + 'md' => Reference::to(App\View\MarkdownRenderer::class), + ], +], +``` + +Now you can use `.md` template files: + +**views/content/help.md** +```markdown +# Help: {{title}} + +Welcome, {{username}}! + +This is a Markdown template with **bold** and *italic* text. + +- Feature 1 +- Feature 2 +- Feature 3 +``` + +## Choosing the Right Template Engine + +**Use PHP templates when:** +- You need maximum flexibility and performance +- Your team is comfortable with PHP +- You want to leverage existing PHP knowledge +- You need complex logic in templates (though this should be minimized) + +**Use Twig templates when:** +- You want stricter separation between logic and presentation +- You work with designers who prefer cleaner syntax +- You need automatic escaping and security features +- You want template inheritance and advanced features + +**Use custom templates when:** +- You have specific requirements not met by PHP or Twig +- You're working with specialized content formats +- You need integration with external template systems + +## Best Practices + +1. **Keep templates simple**: Move complex logic to controllers or services +2. **Always escape output**: Prevent XSS attacks by properly escaping + variables +3. **Use meaningful names**: Name your templates and variables clearly +4. **Organize templates**: Group related templates in subdirectories +5. **Document variables**: Always add type hints for better IDE support +6. **Avoid business logic**: Keep business logic in models and services diff --git a/src/zh-CN/guide/views/view-injections.md b/src/zh-CN/guide/views/view-injections.md new file mode 100644 index 00000000..5a7e5f03 --- /dev/null +++ b/src/zh-CN/guide/views/view-injections.md @@ -0,0 +1,116 @@ +# View injections + +The view injections are designed to provide a standardized way to pass +parameters to the common layer of views in an application. It allows +developers to manage the data that will be available across various views, +ensuring flexibility and reusability of code. + +The view injections could be used if you require `yiisoft/yii-view-renderer` +package: + + +```sh +composer require yiisoft/yii-view-renderer +``` + +## Configuration + +In config `params.php`: + + +```php +... +'yiisoft/yii-view' => [ + 'injections' => [ + Reference::to(ContentViewInjection::class), + Reference::to(CsrfViewInjection::class), + Reference::to(LayoutViewInjection::class), + ], + ], +``` + +## New injections + +Start by defining a class that will implement the +`Yiisoft\Yii\View\Renderer\CommonParametersInjectionInterface`. This class +will be responsible for providing the parameters you want to inject into +your view templates and layouts. + +```php +class MyCustomParametersInjection implements Yiisoft\Yii\View\Renderer\CommonParametersInjectionInterface +{ + // Class properties and methods will go here + + public function __construct(UserService $userService) + { + $this->userService = $userService; + } + + public function getCommonParameters(): array + { + return [ + 'siteName' => 'My Awesome Site', + 'currentYear' => date('Y'), + 'user' => $this->userService->getCurrentUser(), + ]; + } +} +``` + +Add your new Injection to `params.php`: + +```php +'yiisoft/yii-view' => [ + 'injections' => [ + ..., + Reference::to(MyCustomParametersInjection::class), + ], + ], +``` + +## Using Separate Injections for Different Layouts + +If your application has multiple layouts, you can create separate parameter +injections for each layout. This approach allows you to tailor the +parameters injected into each layout according to its specific needs, +enhancing the flexibility and maintainability of your application. + +Create your custom ViewInjection for a specific layout: + +```php +readonly final class CartViewInjection implements CommonParametersInjectionInterface +{ + public function __construct(private Cart $cart) + { + } + + public function getCommonParameters(): array + { + return [ + 'cart' => $this->cart, + ]; + } +} +``` + +Add your new injection to `params.php` under specific layout name. In the +following example, it's `@layout/cart`: + +```php +'yiisoft/yii-view' => [ + 'injections' => [ + ..., + Reference::to(MyCustomParametersInjection::class), + DynamicReference::to(static function (ContainerInterface $container) { + $cart = $container + ->get(Cart::class); + + return new LayoutSpecificInjections( + '@layout/cart', // layout name for injection + + new CartViewInjection($cart) + ); + }), + ], + ], +``` diff --git a/src/zh-CN/guide/views/view.md b/src/zh-CN/guide/views/view.md new file mode 100644 index 00000000..3b256a94 --- /dev/null +++ b/src/zh-CN/guide/views/view.md @@ -0,0 +1,315 @@ +# Views + +View is responsible for presenting data to end users. You give it a template +with some placeholders and presentation logic and some data. The view is +passing data to the template executing template logic. The end result is +ready to be passed to end user, be it a browser, a file to download, an +email to send or something else. + +```mermaid +flowchart LR + A[Data] --> V[View] + B[Template] --> V + V --> C[HTML] + C --> D[Browser] +``` + +In Yii3 views are typically PHP files that contain presentation logic and +HTML markup. The view system provides a flexible way to organize your +presentation layer and supports features like layouts and partial +views. Instead of using plain PHP templates, you can leverage [one of the +template engines such as Twig](template-engines.md). + +## Installation + +For basic view functionality, you need the `yiisoft/view` package: + +```sh +composer require yiisoft/view +``` + +For web applications, you should also install the +`yiisoft/yii-view-renderer` package which provides +[PSR-7](https://www.php-fig.org/psr/psr-7/) compatibility and web-specific +features: + +```sh +composer require yiisoft/yii-view-renderer +``` + +These packages are included by default in the `yiisoft/app` application +template. + +## Basic Concepts + +A view template file contains presentation logic. In the `yiisoft/app` +template, view files are typically stored alongside their controllers (e.g., +`src/Web/Echo/Action.php`). Here's a simple view file example, +`src/Web/Echo/template.php`: + +```php + + +The message is: = Html::encode($message) ?>
+``` + +Here `$message` is a view data that is passed when you render a template +with the help of `ViewRenderer`. For example, `src/Web/Echo/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template', [ + 'message' => $message, + ]); + } +} +``` + +First argument of the `render()` method is a path to the template file. In +the `yiisoft/app`, template files are typically stored alongside their +actions. The result is ready to be rendered to the browser so we return it +immediately. + +## Working with layouts + +Most web applications use a common layout for all pages. In the +`yiisoft/app` template, layouts are stored in `src/Web/Shared/Layout/Main/` +directory. You can set a default layout in `config/common/params.php`: + +```php +return [ + 'yiisoft/yii-view-renderer' => [ + 'viewPath' => null, + 'layout' => '@src/Web/Shared/Layout/Main/layout.php', + ], +]; +``` + +A typical layout file such as `src/Web/Shared/Layout/Main/layout.php` looks +like this: + +```php +register(MainAsset::class); + +$this->addCssFiles($assetManager->getCssFiles()); +$this->addCssStrings($assetManager->getCssStrings()); +$this->addJsFiles($assetManager->getJsFiles()); +$this->addJsStrings($assetManager->getJsStrings()); +$this->addJsVars($assetManager->getJsVars()); + +$this->beginPage() +?> + + + + + + += Html::encode($post->getExcerpt()) ?>
+ += Html::encode($post->getDescription()) ?>
+ +``` + +## Short echo + +Short echo is preferred: + +```php += Html::encode($name) ?> +``` + +## Class methods + +All class methods used in view files must be public regardless if the view +is rendered by the class itself. diff --git a/src/zh-CN/internals/020-package-release.md b/src/zh-CN/internals/020-package-release.md new file mode 100644 index 00000000..de037e15 --- /dev/null +++ b/src/zh-CN/internals/020-package-release.md @@ -0,0 +1,44 @@ +# 020 — Package release + +## Criteria + +- No critical issues. +- Public API changes aren't likely. Some time passed w/o issues reported + that may require API changes. +- All dependencies are stable. +- Close to 100% test coverage with, ideally, a 100% MSI score. +- README is alright. +- Everything is type-hinted unless special cases. +- Psalm analysis passes on at least level 2. +- phpdoc is alright. +- Public API is alright. + +## Release instruction + +Release a package via [Yii Development Tool](005-development-tool.md). + +1. Check that you can sign commits locally (see +[Signing commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)). + +2. Pull last changes from the `master` branch: + +```shell +./yii-dev git/checkout master package-name +./yii-dev git/pull package-name +``` + +3. Check the package for compliance with the criteria above. + +4. Run `release/make` command: + +```shell +./yii-dev release/make package-name +``` + +5. Select the version type (major, minor or path). + +6. On the question "Push commits and tags, and release on GitHub?" check a + diff. If the diff is alright, answer "yes." + +7. For major and minor releases, add a record with release notes on [Yii + Framework News](https://www.yiiframework.com/news). diff --git a/src/zh-CN/internals/021-changelog-upgrade.md b/src/zh-CN/internals/021-changelog-upgrade.md new file mode 100644 index 00000000..ee291e73 --- /dev/null +++ b/src/zh-CN/internals/021-changelog-upgrade.md @@ -0,0 +1,67 @@ +# 021 — Changelog and upgrade + +For all released packages, we've a detailed changelog and upgrade guide. + +## Changelog + +Changelog is written for each version released. The file name is +`CHANGELOG.md`. The format is the following: + +```markdown +# My package Change Log + +## 1.0.2 under development + +- no changes in this release. + +## 1.0.1 March 23, 2021 + +- Bug #42: Short description of the change (@author1, @author2) + +## 1.0.0 February 02, 2021 + +- Initial release. +``` + +There "My package" is the name of the package, `1.0.1` is the version +released followed by release date. For each version, there are a number of +lines listing the changes. "Bug" refers to a change type. The following +types are used: + +- New — New features. +- Chg — General changes. +- Enh — Existing feature enhancements. +- Bug — Bug fixes. + +In the changelog file lines should be ordered as New, Chg, Enh, Bug. + +"#42" above is the number of issue or pull requests corresponding to the +change. "author1" is the GitHub nickname of the code author. "author2" is an +additional author. An author's nickname MUST be prefixed with `@`. + +## Upgrade + +Upgrade guide is created when there is a new major version that isn't +compatible with the previous one. It describes steps necessary to upgrade +application code. + +The file name is `UPGRADE.md`. The format is the following: + +```markdown +# Upgrading Instructions for my package + +This file contains the upgrade notes. These notes highlight changes that could break your +application when you upgrade the package from one version to another. + +> **Important!** The following upgrading instructions are cumulative. That is, if you want +> to upgrade from version A to version C and there is version B between A and C, you need +> to follow the instructions for both A and B. + +## Upgrade from 2.x + +- Public method `test()` was removed. Use `perform()` instead. + +## Upgrade from 1.x + +- Clean up the cache after upgrading. Old cache is not compatible with new code. +``` diff --git a/src/zh-CN/internals/022-config-groups.md b/src/zh-CN/internals/022-config-groups.md new file mode 100644 index 00000000..8193bf82 --- /dev/null +++ b/src/zh-CN/internals/022-config-groups.md @@ -0,0 +1,73 @@ +# 022 — Config groups + +This document defines naming convention for the framework groups used with +[yiisoft/config](https://github.com/yiisoft/config). Note that this isn't a +naming convention for config files. These could be anything and are mapped +to group names via `composer.json`. + +## Config group name postfixes + +- "web" postfix applies to web only that's classic server HTML generation, + REST, RPC, etc. +- "console" postfix applies to console +- If there's no postfix, it's "common" and applies to both web and console +- "web" and "console" may override what's defined in "common" + +## Parameters + +Application config parameters that are used in all configs. + +- `params` — common parameters +- `params-web` — web application parameters +- `params-console` — console application parameters + +## Container + +Configuration for [yiisoft/di](https://github.com/yiisoft/di). + +### Definitions + +- `di` — common container definitions +- `di-web` — web container definitions +- `di-console` — console container definitions + +### Providers + +- `di-providers` — common container providers +- `di-providers-web` — web container providers +- `di-providers-console` — console container providers + +### Delegates + +- `di-delegates` — common container delegates +- `di-delegates-web` — web container delegates +- `di-delegates-console` — console container delegates + +### Tags + +- `di-tags` — common container tags +- `di-tags-web` — web container tags +- `di-tags-console` — console container tags + +## Events + +Configuration for [yiisoft/yii-event](https://github.com/yiisoft/yii-event). + +- `events` — common events +- `events-web` — web events +- `events-console` — console events + +## Bootstrap + +Application bootstrapping for +[yiisoft/yii-runner](https://github.com/yiisoft/yii-runner). + +- `bootstrap` — common bootstrap +- `bootstrap-web` — web bootstrap +- `bootstrap-console` — console bootstrap + +## Others + +- `routes` — [yiisoft/router](https://github.com/yiisoft/router) routes +- `widgets` — [yiisoft/widget](https://github.com/yiisoft/widget) default + widgets configuration diff --git a/src/zh-CN/internals/index.md b/src/zh-CN/internals/index.md new file mode 100644 index 00000000..e512a121 --- /dev/null +++ b/src/zh-CN/internals/index.md @@ -0,0 +1,44 @@ +# Yii Framework Internals + +This section contains documentation for developers contributing to the Yii +framework itself. It covers guidelines, workflows, and best practices for +maintaining and developing Yii packages. + +## Table of Contents + +- [000 — Packages](000-packages.md) - Package structure and naming + conventions +- [001 — Yii goal and values](001-yii-values.md) - Project goals and core + values +- [002 — Issue workflow](002-issue-workflow.md) - How to handle issues +- [003 — Roadmap](003-roadmap.md) - Development roadmap and future plans +- [004 — Namespaces](004-namespaces.md) - Namespace conventions +- [005 — Yii development tool](005-development-tool.md) - Development tools + for Yii packages +- [006 — Git commit messages](006-git-commit-messages.md) - Commit message + format +- [007 — Exceptions](007-exceptions.md) - Exception handling guidelines +- [008 — Interfaces](008-interfaces.md) - Interface design principles +- [009 — Design Decisions](009-design-decisions.md) - Architectural and + design decisions +- [010 — Code style](010-code-style.md) - PHP code style guidelines +- [011 — Error correction](011-error-correction.md) - Error handling and + correction +- [012 — Tests](012-tests.md) - Testing guidelines and practices +- [013 — Code review](013-code-review.md) - Code review process and + guidelines +- [014 — Documentation](014-docs.md) - Documentation writing guidelines +- [015 — PhpStorm metadata and attributes](015-phpstorm.md) - PhpStorm + integration +- [016 — Security workflow](016-security-workflow.md) - Security issue + handling +- [017 — Tags](017-tags.md) - Git tagging conventions +- [018 — Widgets](018-widgets.md) - Widget development guidelines +- [019 — View code style](019-view-code-style.md) - Code style for view + templates +- [020 — Package release](020-package-release.md) - Release process for + packages +- [021 — Changelog and upgrade](021-changelog-upgrade.md) - Maintaining + changelogs and upgrade notes +- [022 — Config groups](022-config-groups.md) - Configuration group + organization