From d6db3ef09fa8b403ae9b6742b46c87adae11a6dd Mon Sep 17 00:00:00 2001
From: Sami Mazouz Hello! something Hello World! {this.counter} {this.attrs.counter} Counter: {app.counter.getCount()} Hello World!{this.showContent ? ' Extra Content!' : ''} Hello World! Hello World ¡Hola! something Hello World! {this.counter} {this.attrs.counter} Counter: {app.counter.getCount()} Hello World!{this.showContent ? ' Extra Content!' : ''} Hello World! Hello World {app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}
+
+ Hello from the settings section!
+ )
+ }
+}
+
+```
+
+Then, simply run `registerPage`:
+
+```js
+
+import StarPage from './components/StarPage';
+
+app.initializers.add('interstellar', function(app) {
+
+ app.extensionData
+ .for('acme-interstellar')
+ .registerPage(StarPage);
+});
+```
+
+This page will be shown instead of the default.
+
+You can extend the [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) or extend the base `Page` and design your own!
+
+## Composer.json Metadata
+
+In beta 15, extension pages make room for extra info which is pulled from extensions' composer.json.
+
+For more information, see the [composer.json schema](https://getcomposer.org/doc/04-schema.md).
+
+| Description | Where in composer.json |
+| ---------------------------------- | ------------------------------------------------------------ |
+| discuss.flarum.org discussion link | "forum" key inside "support" |
+| Documentation | "docs" key inside "support" |
+| Support (email) | "email" key inside "support" |
+| Website | "homepage" key |
+| Donate | "funding" key block (Note: Only the first link will be used) |
+| Source | "source" key inside "support" |
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md
new file mode 100644
index 000000000..9c039fe49
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md
@@ -0,0 +1,58 @@
+# API Throttling
+
+Flarum comes with a builtin `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) for throttling requests to the API. This runs on every API route, and extensions can add their own custom logic to throttle requests.
+
+:::caution Forumsrouten
+
+Some forum routes (login, register, forgot password, etc) work by calling an API route under the surface. The `ThrottleApi` middleware does not currently run for these requests, but that is planned for the future.
+
+:::
+
+## Custom Throttlers
+
+The format for a custom throttler is extremely simple: all you need is a closure or invokable class that takes the current request as an argument, and returns one of:
+
+- `false`: This explicitly bypasses throttling for this request, overriding all other throttlers
+- `true`: This marks the request as to be throttled.
+- `null`: This means that this throttler doesn't apply. Any other outputs will be ignored, with the same effect as `null`.
+
+Throttlers will be run on EVERY request, and are responsible for figuring out whether or not they apply. For example, consider Flarum's post throttler:
+
+```php
+use DateTime;
+use Flarum\Post\Post;
+
+function ($request) {
+ if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) {
+ return;
+ }
+
+ $actor = $request->getAttribute('actor');
+
+ if ($actor->can('postWithoutThrottle')) {
+ return false;
+ }
+
+ if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) {
+ return true;
+ }
+};
+```
+
+Throttlers can be added or removed via the `ThrottleApi` middleware in `extend.php`. For example:
+
+```php
+set('throttleAll', function () {
+ return false;
+ })
+ ->remove('bypassThrottlingAttribute'),
+ // Other extenders
+];
+```
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api.md
new file mode 100644
index 000000000..073d858e1
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api.md
@@ -0,0 +1,353 @@
+# API and Data Flow
+
+In the [previous article](models.md), we learned how Flarum uses models to interact with data. Here, we'll learn how to get that data from the database to the JSON-API to the frontend, and all the way back again.
+
+:::info
+
+To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md).
+
+:::
+
+## API Request Lifecycle
+
+Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request:
+
+
+
+1. An HTTP request is sent to Flarum's API. Typically, this will come from the Flarum frontend, but external programs can also interact with the API. Flarum's API mostly follows the [JSON:API](https://jsonapi.org/) specification, so accordingly, requests should follow [said specification](https://jsonapi.org/format/#fetching).
+2. The request is run through [middleware](middleware.md), and routed to the proper controller. You can learn more about controllers as a whole on our [routes and content documentation](routes.md). Assuming the request is to the API (which is the case for this section), the controller that handles the request will be a subclass of `Flarum\Api\AbstractSerializeController`.
+3. Any modifications done by extensions to the controller via the [`ApiController` extender](#extending-api-controllers) are applied. This could entail changing sort, adding includes, changing the serializer, etc.
+4. The `$this->data()` method of the controller is called, yielding some raw data that should be returned to the client. Typically, this data will take the form of a Laravel Eloquent model collection or instance, which has been retrieved from the database. That being said, the data could be anything as long as the controller's serializer can process it. Each controller is responsible for implementing its own `data` method. Note that for `PATCH`, `POST`, and `DELETE` requests, `data` will perform the operation in question, and return the modified model instance.
+5. That data is run through any pre-serialization callbacks that extensions register via the [`ApiController` extender](#extending-api-controllers).
+6. The data is passed through a [serializer](#serializers), which converts it from the backend, database-friendly format to the JSON:API format expected by the frontend. It also attaches any related objects, which are run through their own serializers. As we'll explain below, extensions can [add / override relationships and attributes](#attributes-and-relationships) at the serialization level.
+7. The serialized data is returned as a JSON response to the frontend.
+8. If the request originated via the Flarum frontend's `Store`, the returned data (including any related objects) will be stored as [frontend models](#frontend-models) in the frontend store.
+
+## API Endpoints
+
+We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints.
+
+As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are:
+
+- Listing instances of a model (possibly including searching/filtering)
+- Getting a single model instance
+- Creating a model instance
+- Updating a model instance
+- Deleting a single model instance
+
+We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender:
+
+```php
+ (new Extend\Routes('api'))
+ ->get('/tags', 'tags.index', ListTagsController::class)
+ ->get('/tags/{id}', 'tags.show', ShowTagController::class)
+ ->post('/tags', 'tags.create', CreateTagController::class)
+ ->patch('/tags/{id}', 'tags.update', UpdateTagController::class)
+ ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class)
+```
+
+:::caution
+
+Paths to API endpoints are not arbitrary! To support interactions with frontend models:
+
+- The path should either be `/prefix/{id}` for get/update/delete, or `/prefix` for list/create.
+- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`).
+- The methods must match the example above.
+
+Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique!
+
+:::
+
+The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources.
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically create your endpoint controllers:
+```bash
+$ flarum-cli make backend api-controller
+```
+
+:::
+
+### Listing Resources
+
+For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`.
+
+```php
+use Flarum\Api\Controller\AbstractListController;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class ListTagsController extends AbstractListController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ return Tag::all();
+ }
+}
+```
+
+#### Pagination
+
+You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller:
+
+```php
+ // The number of records included by default.
+ public $limit = 20;
+
+ // The maximum number of records that can be requested.
+ public $maxLimit = 50;
+```
+
+You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods:
+
+```php
+$limit = $this->extractLimit($request);
+$offset = $this->extractOffset($request);
+
+return Tag::skip($offset)->take($limit);
+```
+
+To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method.
+
+#### Sorting
+
+You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller:
+
+```php
+ // The default sort field and order to use.
+ public $sort = ['name' => 'asc'];
+
+ // The fields that are available to be sorted by.
+ public $sortFields = ['firstName', 'lastName'];
+```
+
+You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query:
+
+```php
+use Illuminate\Support\Str;
+
+// ...
+
+$sort = $this->extractSort($request);
+$query = Tag::query();
+
+foreach ($sort as $field => $order) {
+ $query->orderBy(Str::snake($field), $order);
+}
+
+return $query->get();
+```
+
+#### Searching and Filtering
+
+Read our [searching and filtering](search.md) guide for more information!
+
+### Showing a Resource
+
+For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers).
+
+```php
+use Flarum\Api\Controller\AbstractShowController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class ShowTagController extends AbstractShowController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ $id = Arr::get($request->getQueryParams(), 'id');
+
+ return Tag::findOrFail($id);
+ }
+}
+```
+
+### Creating a Resource
+
+For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`:
+
+```php
+use Flarum\Api\Controller\AbstractCreateController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class CreateTagController extends AbstractCreateController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ $attributes = Arr::get($request->getParsedBody(), 'data.attributes');
+
+ return Tag::create([
+ 'name' => Arr::get($attributes, 'name')
+ ]);
+ }
+}
+```
+
+### Updating a Resource
+
+For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`.
+
+### Deleting a Resource
+
+For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response.
+
+```php
+use Flarum\Api\Controller\AbstractDeleteController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+class DeleteTagController extends AbstractDeleteController
+{
+ protected function delete(Request $request)
+ {
+ $id = Arr::get($request->getQueryParams(), 'id');
+
+ Tag::findOrFail($id)->delete();
+ }
+}
+```
+
+### Including Relationships
+
+To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller:
+
+```php
+ // The relationships that are included by default.
+ public $include = ['user'];
+
+ // Other relationships that are available to be included.
+ public $optionalInclude = ['discussions'];
+```
+
+You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized:
+
+```php
+$relations = $this->extractInclude($request);
+
+return Tag::all()->load($relations);
+```
+
+### Extending API Controllers
+
+It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender
+
+```php
+use Flarum\Api\Event\WillGetData;
+use Flarum\Api\Controller\ListDiscussionsController;
+use Illuminate\Contracts\Events\Dispatcher;
+
+return [
+ (new Extend\ApiController(ListDiscussionsController::class))
+ ->setSerializer(MyDiscussionSerializer::class)
+ ->addInclude('user')
+ ->addOptionalInclude('posts')
+ ->setLimit(20)
+ ->setMaxLimit(50)
+ ->setSort(['name' => 'asc'])
+ ->addSortField('firstName')
+ ->prepareDataQuery(function ($controller) {
+ // Add custom logic here to modify the controller
+ // before data queries are executed.
+ })
+]
+```
+
+The `ApiController` extender can also be used to adjust data before serialization
+
+```php
+use Flarum\Api\Event\WillSerializeData;
+use Flarum\Api\Controller\ListDiscussionsController;
+use Illuminate\Contracts\Events\Dispatcher;
+
+return [
+ (new Extend\ApiController(ListDiscussionsController::class))
+ ->prepareDataForSerialization(function ($controller, $data, $request, $document) {
+ $data->load('myCustomRelation');
+ }),
+]
+```
+
+## Serializers
+
+Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library.
+
+A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument:
+
+```php
+use Flarum\Api\Serializer\AbstractSerializer;
+use Flarum\Api\Serializer\UserSerializer;
+
+class DiscussionSerializer extends AbstractSerializer
+{
+ protected $type = 'discussions';
+
+ protected function getDefaultAttributes($discussion)
+ {
+ return [
+ 'title' => $discussion->title,
+ ];
+ }
+}
+```
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically create your serializer:
+```bash
+$ flarum-cli make backend api-serializer
+```
+
+:::
+
+### Attributes and Relationships
+
+You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources.
+
+```php
+ protected function user($discussion)
+ {
+ return $this->hasOne($discussion, UserSerializer::class);
+ }
+```
+
+### Extending Serializers
+
+To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender:
+
+```php
+use Flarum\Api\Serializer\UserSerializer;
+
+return [
+ (new Extend\ApiSerializer(UserSerializer::class))
+ // One attribute at a time
+ ->attribute('firstName', function ($serializer, $user, $attributes) {
+ return $user->first_name
+ })
+ // Multiple modifications at once, more complex logic
+ ->mutate(function($serializer, $user, $attributes) {
+ $attributes['someAttribute'] = $user->someAttribute;
+ if ($serializer->getActor()->can('administrate')) {
+ $attributes['someDate'] = $serializer->formatDate($user->some_date);
+ }
+
+ return $attributes;
+ })
+ // API relationships
+ ->hasOne('phone', PhoneSerializer::class)
+ ->hasMany('comments', CommentSerializer::class),
+]
+```
+
+### Non-Model Serializers and `ForumSerializer`
+
+Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`.
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/assets.md
new file mode 100644
index 000000000..16b401fc3
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/assets.md
@@ -0,0 +1,7 @@
+# Extension Assets
+
+Some extensions might want to include assets like images or JSON files in their source code (note that this is not the same as uploads, which would probably require a [filesystem disk](filesystem.md)).
+
+This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed.
+
+If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example.
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md
new file mode 100644
index 000000000..338bbd06f
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md
@@ -0,0 +1,206 @@
+# Authorization
+
+As with any framework, Flarum allows certain actions and content to be restricted to certain users. There are 2 parallel systems for this:
+
+- The authorization process dictates whether a user can take a certain action.
+- Visibility scoping can be applied to a database query to efficiently restrict the records that users can access. This is documented in our [model visibility](model-visibility.md) article.
+
+## Authorization Process
+
+The authorization process is used to check whether a person is allowed to perform certain actions. For instance, we want to check if a user is authorized before they:
+
+- Access the admin dashboard
+- Start a discussion
+- Edit a post
+- Update another user's profile
+
+Each of these is determined by unique criteria: in some cases a flag is sufficient; otherwise, we might need custom logic.
+
+## How It Works
+
+Authorization queries are made with 3 parameters, with logic contained in [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/access/gate):
+
+1. The actor: the user attempting to perform the action
+2. The ability: a string representing the action the actor is attempting
+3. The arguments: usually an instance of a database model which is the subject of the attempted ability, but could be anything.
+
+First, we run the entire request (all three parameters) through all [policies](#policies) registered by extensions and core. Policies are blocks of logic provided by core and extensions that determine whether the actor can perform the ability on the arguments. Policies can return one of the following:
+
+- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`)
+- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`)
+- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`)
+- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`)
+
+Policy results are considered in the priority `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. For example, if a single policy returns `FORCE_DENY`, all other policies will be ignored. If one policy returns `DENY` and 10 policies return `ALLOW`, the request will be denied. This allows decisions to be made regardless of the order in which extensions are booted. Note that policies are extremely powerful: if access is denied at the policy stage, that will override group permissions and even admin privileges.
+
+Secondly, if all policies return null (or don't return anything), we check if the user is in a group that has a permission equal to the ability (note that both permissions and abilities are represented as strings). If so, we authorize the action. See our [Groups and Permissions documentation](permissions.md) for more information on permissions.
+
+Then, if the user is in the admin group, we will authorize the action.
+
+Finally, as we have exhausted all checks, we will assume that the user is unauthorized and deny the request.
+
+## How To Use Authorization
+
+Flarum's authorization system is accessible through public methods of the `Flarum\User\User` class. The most important ones are listed below; others are documented in our [PHP API documentation](https://api.docs.flarum.org/php/master/flarum/user/user).
+
+
+In this example, we will use `$actor` as an instance of `Flarum\User\User`, `'viewForum'` and `'reply'` as examples of abilities, and `$discussion` (instance of `Flarum\Discussion\Discussion`) as an example argument.
+
+```php
+// Check whether a user can perform an action.
+$canDoSomething = $actor->can('viewForum');
+
+// Check whether a user can perform an action on a subject.
+$canDoSomething = $actor->can('reply', $discussion);
+
+// Raise a PermissionDeniedException if a user cannot perform an action.
+$actor->assertCan('viewForum');
+$actor->assertCan('reply', $discussion);
+
+// Raise a NotAuthenticatedException if the user is not logged in.
+$actor->assertRegistered();
+
+// Raise a PermissionDeniedException if the user is not an admin.
+$actor->assertAdmin();
+
+// Check whether one of the user's groups have a permission.
+// WARNING: this should be used with caution, as it doesn't actually
+// run through the authorization process, so it doesn't account for policies.
+// It is, however, useful in implementing custom policies.
+$actorHasPermission = $actor->hasPermission(`viewForum`);
+```
+
+## Custom Policies
+
+Policies allow us to use custom logic beyond simple groups and permissions when evaluating authorization for an ability with a subject. For instance:
+
+- We want to allow users to edit posts even if they aren't moderators, but only their own posts.
+- Depending on settings, we might allow users to rename their own discussions indefinitely, for a short period of time after posting, or not at all.
+
+As described [above](#how-it-works), on any authorization check, we query all policies registered for the target's model, or any parent classes of the target's model. If no target is provided, any policies registered as `global` will be applied.
+
+So, how does a policy get "checked"?
+
+First, we check if the policy class has a method with the same name as the ability being evaluated. If so, we run it with the actor and subject as parameters. If that method returns a non-null value, we return that result. Otherwise, we continue to the next step (not necessarily the next policy).
+
+Then, we check if the policy class has a method called `can`. If so, we run it with the actor, ability, and subject, and return the result.
+
+If `can` doesn't exist or returns null, we are done with this policy, and we proceed to the next one.
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically generate policies:
+```bash
+$ flarum-cli make backend policy
+```
+
+:::
+
+### Example Policies
+
+Let's take a look at an example policy from [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access):
+
+```php
+is_restricted) {
+ return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny();
+ }
+ }
+
+ /**
+ * @param User $actor
+ * @param Tag $tag
+ * @return bool|null
+ */
+ public function addToDiscussion(User $actor, Tag $tag)
+ {
+ return $this->startDiscussion($actor, $tag);
+ }
+}
+```
+
+We can also have global policies, which are run when `$user->can()` is called without a target model instance. Again from Tags:
+
+```php
+settings = $settings;
+ }
+
+ /**
+ * @param Flarum\User\User $actor
+ * @param string $ability
+ * @return bool|void
+ */
+ public function can(User $actor, string $ability)
+ {
+ if (in_array($ability, ['viewForum', 'startDiscussion'])) {
+ $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags');
+ $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags');
+
+ if ($enoughPrimary && $enoughSecondary) {
+ return $this->allow();
+ } else {
+ return $this->deny();
+ }
+ }
+ }
+}
+```
+
+### Registering Policies
+
+Both model-based and global policies can be registered with the `Policy` extender in your `extend.php` file:
+
+```php
+use Flarum\Extend;
+use Flarum\Tags\Tag;
+use YourNamespace\Access;
+
+return [
+ // Other extenders
+ (new Extend\Policy())
+ ->modelPolicy(Tag::class, Access\TagPolicy::class)
+ ->globalPolicy(Access\GlobalPolicy::class),
+ // Other extenders
+];
+```
+
+## Frontend Authorization
+
+Commonly, you'll want to use authorization results in frontend logic. For example, if a user doesn't have permission to see search users, we shouldn't send requests to that endpoint. And if a user doesn't have permission to edit users, we shouldn't show menu items for that.
+
+Because we can't do authorization checks in the frontend, we have to perform them in the backend, and attach them to serialization of data we're sending. Global permissions (`viewForum`, `viewUserList`) can be included on the `ForumSerializer`, but for object-specific authorization, we may want to include those with the subject object. For instance, when we return lists of discussions, we check whether the user can reply, rename, edit, and delete them, and store that data on the frontend discussion model. It's then accessible via `discussion.canReply()` or `discussion.canEdit()`, but there's nothing magic there: it's just another attribute sent by the serializer.
+
+For an example of how to attach data to a serializer, see a [similar case for transmitting settings](settings.md#accessing-settings).
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md
new file mode 100644
index 000000000..25142b030
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md
@@ -0,0 +1,172 @@
+# Backend Events
+
+Often, an extension will want to react to some events occuring elsewhere in Flarum. For instance, we might want to increment a counter when a new discussion is posted, send a welcome email when a user logs in for the first time, or add tags to a discussion before saving it to the database. These events are known as **domain events**, and are broadcasted across the framework through [Laravel's event system](https://laravel.com/docs/8.x/events).
+
+For a full list of backend events, see our [API documentation](https://api.docs.flarum.org/php/master/search.html?search=Event). Domain events classes are organized by namespace, usually `Flarum\TYPE\Event`.
+
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically generate event listeners:
+```bash
+$ flarum-cli make backend event-listener
+```
+
+:::
+
+## Listening to Events
+
+You can attach a listener to an event using the [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event) [extender](start.md#extenders):
+
+```php
+use Flarum\Extend;
+use Flarum\Post\Event\Deleted;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+
+return [
+ (new Extend\Event)
+ ->listen(Deleted::class, function($event) {
+ // do something here
+ })
+ ->listen(Deleted::class, PostDeletedListener::class)
+];
+```
+```php
+class PostDeletedListener
+{
+ protected $translator;
+
+ public function __construct(TranslatorInterface $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public function handle(Deleted $event)
+ {
+ // Your logic here
+ }
+}
+```
+
+As shown above, a listener class can be used instead of a callback. This allows you to [inject dependencies](https://laravel.com/docs/8.x/container) into your listener class via constructor parameters. In this example we resolve a translator instance, but we can inject anything we want/need.
+
+You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts:
+
+```php
+use Flarum\Extend;
+use Flarum\Post\Event\Deleted;
+use Flarum\Post\Event\Saving;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+
+return [
+ (new Extend\Event)
+ ->subscribe(PostEventSubscriber::class),
+];
+```
+```php
+class PostEventSubscriber
+{
+ protected $translator;
+
+ public function __construct(TranslatorInterface $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public function subscribe($events)
+ {
+ $events->listen(Deleted::class, [$this, 'handleDeleted']);
+ $events->listen(Saving::class, [$this, 'handleSaving']);
+ }
+
+ public function handleDeleted(Deleted $event)
+ {
+ // Your logic here
+ }
+
+ public function handleSaving(Saving $event)
+ {
+ // Your logic here
+ }
+}
+```
+
+## Dispatching Events
+
+Dispatching events is very simple. All you need to do is inject `Illuminate\Contracts\Events\Dispatcher` into your class, and then call its `dispatch` method. For instance:
+
+```php
+use Flarum\Post\Event\Deleted;
+use Illuminate\Contracts\Events\Dispatcher;
+
+
+class SomeClass
+{
+ /**
+ * @var Dispatcher
+ */
+ protected $events;
+
+ /**
+ * @param Dispatcher $events
+ */
+ public function __construct(Dispatcher $events)
+ {
+ $this->events = $events;
+ }
+
+ public function someMethod()
+ {
+ // Logic
+ $this->events->dispatch(
+ new Deleted($somePost, $someActor)
+ );
+ // More Logic
+ }
+}
+```
+
+## Custom Events
+
+As an extension developer you can define your own events to allow yourself (or other extensions) to react to events in your extension. Events are generally instances of simple classes (no need to extend anything). When defining a new event, you'll typically want to use public properties, and maybe some methods for convenience of users. For example, if we take a look at `Flarum\Post\Event\Deleted`, it's just a wrapping around some data:
+
+```php
+post = $post;
+ $this->actor = $actor;
+ }
+}
+```
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/cli.md
new file mode 100644
index 000000000..ee92962b8
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/cli.md
@@ -0,0 +1,15 @@
+# Flarum CLI
+
+The Flarum development ecosystem is oriented around many small, modules, interacting extensions. This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions.
+
+We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle.
+
+Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10).
+
+See the [package's readme](https://github.com/flarum/cli#readme) for information on:
+
+- Installation
+- Usage
+- Upgrading
+- Available commands
+- Some implementation details, if you're interested
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/console.md
new file mode 100644
index 000000000..31aa2b87d
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/console.md
@@ -0,0 +1,70 @@
+# Konsole
+
+Flarum allows extension developers to add custom console commands in addition to the [default ones](../console.md) provided by flarum core.
+
+All console command development is done in the backend using PHP. To create a custom console command, you'll need to create a class that extends `\Flarum\Console\AbstractCommand`.
+
+```php
+use Flarum\Console\AbstractCommand;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+
+class YourCommand extends AbstractCommand {
+ protected function configure()
+ {
+ $this
+ ->setName('YOUR COMMAND NAME')
+ ->setDescription('YOUR COMMAND DESCRIPTION');
+ }
+ protected function fire()
+ {
+ // Your logic here!
+ }
+}
+```
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically generate and register a console command:
+```bash
+$ flarum-cli make backend command
+```
+
+:::
+
+## Registering Console Commands
+
+To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file:
+
+```php
+use Flarum\Extend;
+use YourNamespace\Console\CustomCommand;
+
+return [
+ // Other extenders
+ (new Extend\Console())->command(CustomCommand::class)
+ // Other extenders
+];
+```
+
+## Scheduled Commands
+
+The `Flarum\Extend\Console`'s `schedule` method allows extension developers to create scheduled commands that run on an interval:
+
+
+```php
+use Flarum\Extend;
+use YourNamespace\Console\CustomCommand;
+use Illuminate\Console\Scheduling\Event;
+
+return [
+ // Other extenders
+ (new Extend\Console())->schedule('cache:clear', function (Event $event) {
+ $event->everyMinute();
+ }, ['Arg1', '--option1', '--option2']),
+ // Other extenders
+];
+```
+
+In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information.
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md
new file mode 100644
index 000000000..7061d5aa0
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md
@@ -0,0 +1,40 @@
+# Distribution
+
+You've written a great extension — and now you want the whole world to be able to use it. This document will take you through the process of distribution, from setting up a Git repository for your extension, to publishing it on Packagist.
+
+## Setting Up Git
+
+The first thing you'll need to do is set up a version control system (VCS). The most popular VCS is [Git](https://git-scm.com/). In this guide we'll be using Git, so make sure you have it [installed](https://git-scm.com/downloads) before continuing. If you don't have much Git knowledge, you may want to check out [these learning resources](https://try.github.io/).
+
+After you have installed Git, you'll need to initialize your repository. You can use `git init` on the command line if you're comfortable, or use a GUI tool like [SourceTree](https://www.sourcetreeapp.com/) or [GitKraken](https://www.gitkraken.com/).
+
+Then, you'll need an account in a Git hosting server, the most popular being [GitHub](https://github.com) and [GitLab](https://gitlab.com). These will instruct you on how to hook up your local repository with the online "remote" repository.
+
+## Tagging a Release
+
+As you are going to be publishing this extension, you'll want to make sure that the information is up to date. Take a minute to revisit `composer.json` and make sure package name, description, and Flarum extension information are all correct. It is recommended to have a `README.md` file in your repository to explain what the extension is, so create one if you haven't already.
+
+When you're ready to release, commit your extension's files to the repo and tag your first version:
+
+```bash
+git tag v0.1.0
+git push && git push --tags
+```
+
+## Publishing on Packagist
+
+Composer packages are published to a Composer repository, usually [Packagist](https://packagist.org/). You will need an account to proceed.
+
+If this is the first release you are publishing of your extension, you will need to [submit your package](https://packagist.org/packages/submit) using its public repository URL. If your extension is located on GitHub, this URL will look something like `https://github.com/AUTHOR/NAME.git`.
+
+### Future Releases
+
+You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server.
+
+## Promoting Your Extension
+
+You will most likely want to create a discussion on the Flarum Community in the [Extensions tag](https://discuss.flarum.org/t/extensions). Other people can install your extension using the following command:
+
+```bash
+composer require vendor/package
+```
\ No newline at end of file
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md
new file mode 100644
index 000000000..7a8db4f8c
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md
@@ -0,0 +1,122 @@
+# Extending Extensions
+
+Flarum extensions aren't just for adding features to core: extensions can extend other extensions!
+
+:::tip
+
+To learn how to make your extension extensible, see the [relevant documentation](extensibility.md)
+
+:::
+
+## Dependencies
+
+If your extension relies on another extension, you'll want to ensure that:
+
+- The other extension is installed and enabled before yours can be.
+- The other extension can't be disabled while yours is enabled.
+- The other extension is booted before your extension.
+
+Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section.
+
+For example, if you were building a new theme for the Flarum Tags extension, your `composer.json` would look like this:
+
+```json
+{
+ // ...
+ "require": {
+ "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core.
+ "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension.
+ },
+ // ...
+}
+```
+
+## Optional Dependencies
+
+Sometimes, extension A might want to extend extension B only if extension B is enabled. In this case, we call B an "Optional Dependency" of A. For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled.
+
+The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. For instance:
+
+```js
+if ('some-extension-id' in flarum.extensions) {
+ // do something
+}
+```
+
+In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. For instance:
+
+```php
+extensions = $extensions;
+ }
+
+ public function someMethod()
+ {
+ if ($this->extensions->isEnabled('some-extension-id')) {
+ // do something.
+ }
+ }
+}
+```
+
+Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json.
+
+For instance:
+
+```json
+{
+ // ...
+ "extra": {
+ "flarum-extension": {
+ "optional-dependencies": [
+ "flarum/tags"
+ ]
+ }
+ },
+ // ...
+}
+```
+
+## Importing from Extensions
+
+In the backend, you can import the classes you need via regular PHP `use` statements:
+
+```php
+ {
+ // Your Extension Code Here
+})
+
+export {
+ // Put all the stuff you want to export here.
+}
+```
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md
new file mode 100644
index 000000000..ef202b2c7
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md
@@ -0,0 +1,129 @@
+# Filesystem
+
+Flarum core integrates with the filesystem to store and serve assets (like compiled JS/CSS or upload logos/favicons) and avatars.
+
+Extensions can use Flarum's provided utils for their own filesystem interaction and file storage needs. This system is based around [Laravel's filesystem tools](https://laravel.com/docs/8.x/filesystem), which are in turn based on the [Flysystem library](https://github.com/thephpleague/flysystem).
+
+## Disks
+
+Filesystem **disks** represent storage locations, and are backed by storage drivers, which we'll cover later. Flarum core has 2 disks: `flarum-assets` and `flarum-avatars`.
+
+### Using existing disks
+
+To access a disk, you'll need to retrieve it from the [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). To do so, you should inject the factory contract in your class, and access the disks you need.
+
+Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example:
+
+```php
+settings = $settings;
+ $this->uploadDir = $filesystemFactory->disk('flarum-assets');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function delete(ServerRequestInterface $request)
+ {
+ RequestUtil::getActor($request)->assertAdmin();
+
+ $path = $this->settings->get('logo_path');
+
+ $this->settings->set('logo_path', null);
+
+ if ($this->uploadDir->exists($path)) {
+ $this->uploadDir->delete($path);
+ }
+
+ return new EmptyResponse(204);
+ }
+}
+```
+
+The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource.
+
+### Declaring new disks
+
+Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`.
+
+This can be done via the `Filesystem` extender:
+
+```php
+use Flarum\Extend;
+
+return [
+ (new Extend\Filesystem)
+ ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) {
+ return [
+ 'root' => "$paths->public/assets/uploads",
+ 'url' => $url->to('forum')->path('assets/uploads')
+ ];
+ });
+```
+
+Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem.
+
+The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored.
+
+## Storage drivers
+
+Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver.
+
+You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender:
+
+```php
+use Flarum\Extend;
+
+return [
+ (new Extend\Filesystem)
+ ->driver('aws-with-cdn', AwsWithCdnDriver::class);
+```
+
+Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer.
+
+:::danger
+
+Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed.
+
+:::
+
+## GUI and Admin Configuration
+
+Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. For now, extensions are responsible for providing a GUI for their disks and drivers.
+
+As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings.
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md
new file mode 100644
index 000000000..d4ea23b12
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md
@@ -0,0 +1,42 @@
+# Formatting
+
+Flarum uses the powerful [s9e TextFormatter](https://github.com/s9e/TextFormatter) library to format posts from plain markup into HTML. You should become familiar with [how TextFormatter works](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) before you attempt to extend it.
+
+In Flarum, post content is formatted with a minimal TextFormatter configuration by default. The bundled **Markdown** and **BBCode** extensions simply enable the respective plugins on this TextFormatter configuration.
+
+## Configuration
+
+You can configure the TextFormatter `Configurator` instance, as well as run custom logic during parsing and rendering, using the `Formatter` extender:
+
+```php
+use Flarum\Extend;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use s9e\TextFormatter\Configurator;
+use s9e\TextFormatter\Parser;
+use s9e\TextFormatter\Renderer;
+
+return [
+ (new Extend\Formatter)
+ // Add custom text formatter configuration
+ ->configure(function (Configurator $config) {
+ $config->BBCodes->addFromRepository('B');
+ })
+ // Modify raw text before it is parsed.
+ // This callback should return the modified text.
+ ->parse(function (Parser $parser, $context, $text) {
+ // custom logic here
+ return $newText;
+ })
+ // Modify the XML to be rendered before rendering.
+ // This callback should return the new XML.
+ // For example, in the mentions extension, this is used to
+ // provide the username and display name of the user being mentioned.
+ // Make sure that the last $request argument is nullable (or omitted entirely).
+ ->render(function (Renderer $renderer, $context, $xml, Request $request = null) {
+ // custom logic here
+ return $newXml;
+ })
+];
+```
+
+With a good understanding of TextFormatter, this will allow you to achieve anything from simple BBCode tag additions to more complex formatting tasks like Flarum's **Mentions** extension.
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/forms.md
new file mode 100644
index 000000000..af8d74fb6
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/forms.md
@@ -0,0 +1,108 @@
+# Forms and Requests
+
+In this article, we'll go over some frontend tools that are available to us for building and managing forms, as well how to send HTTP requests via Flarum.
+
+## Form Components
+
+As with any interactive site, you will likely want to include forms in some pages and modals. Flarum provides some components to make building (and styling!) these forms easier. Please see the linked API documentation for each of these to learn more about its accepted attrs.
+
+- The [`flarum/common/components/FieldSet` component](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) wraps its children in a HTML fieldset tag, with a legend.
+- The [`flarum/common/components/Select` component](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) is a stylized select input.
+- The [`flarum/common/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) and [`flarum/common/components/Checkbox` components](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) are stylized checkbox input components. Their `loading` attr can be set to `true` to show a loading indicator.
+- The [`flarum/common/components/Button` component](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) is a stylized button, and is used frequently throughout Flarum.
+
+You'll typically want to assign logic for reacting to input changes via Mithril's `on*` attrs, not external listeners (as is common with jQuery or plain JS). For example:
+
+```jsx
+import Component from 'flarum/common/Component';
+import FieldSet from 'flarum/common/components/FieldSet';
+import Button from 'flarum/common/components/Button';
+import Switch from 'flarum/common/components/Switch';
+
+
+class FormComponent extends Component {
+ oninit(vnode) {
+ this.textInput = "";
+ this.booleanInput = false;
+ }
+
+ view() {
+ return (
+
+ )
+ }
+
+ onsubmit() {
+ // Some form handling logic here
+ }
+}
+```
+
+Don't forget to use [translations](i18n.md)!
+
+
+## Streams, bidi, and withAttr
+
+Flarum provides [Mithril's Stream](https://mithril.js.org/stream.html) as `flarum/common/util/Stream`. This is a very powerful reactive data structure, but is most commonly used in Flarum as a wrapper for form data. Its basic usage is:
+
+```js
+import Stream from 'flarum/common/utils/Stream';
+
+
+const value = Stream("hello!");
+value() === "hello!"; // true
+value("world!");
+value() === "world!"; // true
+```
+
+In Flarum forms, streams are frequently used together with the bidi attr. Bidi stands for bidirectional binding, and is a common pattern in frontend frameworks. Flarum patches Mithril with the [`m.attrs.bidi` library](https://github.com/tobyzerner/m.attrs. This abstracts away input processing in Mithril. For instance:
+
+```jsx
+import Stream from 'flarum/common/utils/Stream';
+
+const value = Stream();
+
+// Without bidi
+ value(e.target.value)}>
+
+// With bidi
+
+```
+
+You can also use the `flarum/common/utils/withAttr` util for simplified form processing. `withAttr` calls a callable, providing as an argument some attr of the DOM element tied to the component in question:
+
+```jsx
+import Stream from 'flarum/common/utils/Stream';
+import withAttr from 'flarum/common/utils/withAttr';
+
+const value = Stream();
+
+// With a stream
+
+
+// With any callable
+ {
+ // Some custom logic here
+})}>
+```
+
+## Making Requests
+
+In our [models](models.md) documentation, you learned how to work with models, and save model creation, changes, and deletion to the database via the Store util, which is just a wrapper around Flarum's request system, which itself is just a wrapper around [Mithril's request system](https://mithril.js.org/request.html).
+
+Flarum's request system is available globally via `app.request(options)`, and has the following differences from Mithril's `m.request(options)`:
+
+- It will automatically attach `X-CSRF-Token` headers.
+- It will convert `PATCH` and `DELETE` requests into `POST` requests, and attach a `X-HTTP-Method-Override` header.
+- If the request errors, it will show an alert which, if in debug mode, can be clicked to show a full error modal.
+- You can supply a `background: false` option, which will run the request synchronously. However, this should almost never be done.
+
+Otherwise, the API for using `app.request` is the same as that for `m.request`.
diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md
new file mode 100644
index 000000000..396292ad1
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md
@@ -0,0 +1,218 @@
+# Frontend Pages and Resolvers
+
+As explained in the [Routes and Content](routes.md#frontend-routes) documentation, we can use Mithril's routing system to show different [components](frontend.md#components) for different routes. Mithril allows you to use any component you like, even a Modal or Alert, but we recommend sticking to component classes that inherit the `Page` component.
+
+## The Page Component
+
+We provide `flarum/common/components/Page` as a base class for pages in both the `admin` and `forum` frontends. It has a few benefits:
+
+- Automatically updates [`app.current` and `app.previous` PageState](#pagestate) when switching from one route to another.
+- Automatically closes the modal and drawer when switching from one route to another.
+- Applies `this.bodyClass` (if defined) to the '#app' HTML element when the page renders.
+- It's also good for consistency's sake to use a common base class for all pages.
+- If the page's `scrollTopOnCreate` attribute is set to `false` in `oninit`, the page won't be scrolled to the top when changed.
+- If the page's `useBrowserScrollRestoration` is set to `false` in `oninit`, the browser's automatic scroll restoration won't be used on that page.
+
+Page components work just like any other inherited component. For a (very simple) example:
+
+```js
+import Page from 'flarum/common/components/Page';
+
+
+export default class CustomPage extends Page {
+ view() {
+ return {app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}
+
+ ¡Hola desde la sección de ajustes!
+ )
+ }
+}
+
+```
+
+En la beta 15, las páginas de las extensiones tienen espacio para información extra que se extrae del composer.json de las extensiones.
+
+```js
+
+import StarPage from './components/StarPage';
+
+app.initializers.add('interstellar', function(app) {
+
+ app.extensionData
+ .for('acme-interstellar')
+ .registerPage(StarPage);
+});
+```
+
+Para más información, consulte el esquema [composer.json](https://getcomposer.org/doc/04-schema.md).
+
+You can extend the [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) or extend the base `Page` and design your own!
+
+## Metadatos del Composer.json
+
+En la beta 15, las páginas de las extensiones tienen espacio para información extra que se extrae del composer.json de las extensiones.
+
+Para más información, consulte el esquema (schema) [composer.json](https://getcomposer.org/doc/04-schema.md).
+
+| Descripción | Dónde en composer.json |
+| -------------------------------------- | --------------------------------------------------------------------- |
+| Enlace de discusión discuss.flarum.org | Clave "forum" dentro de "support" |
+| Documentación | Clave "docs" dentro de "support" |
+| Soporte (correo electrónico) | Clave "email" dentro de "support" |
+| Sitio web | Clave "homepage" |
+| Donación | Bloque de claves "funding" (Nota: Sólo se utilizará el primer enlace) |
+| Fuente | Clave "source" dentro de "support" |
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md
new file mode 100644
index 000000000..8d776b680
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md
@@ -0,0 +1,62 @@
+# Aceleración de la API
+
+Flarum viene con un `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) para acelerar las peticiones a la API. Esto se ejecuta en cada ruta de la API, y las extensiones pueden añadir su propia lógica personalizada para acelerar las solicitudes.
+
+:::caution Rutas del Foro
+
+Algunas rutas del foro (inicio de sesión, registro, olvido de contraseña, etc) funcionan llamando a una ruta de la API bajo la superficie. El middleware `ThrottleApi` no se ejecuta actualmente para estas peticiones, pero está previsto para el futuro.
+
+:::
+
+## Aceleradores personalizados
+
+El formato de un acelerador personalizado es extremadamente simple: todo lo que necesitas es un cierre o clase invocable que tome la petición actual como argumento, y devuelva una de las siguientes opciones
+
+- `false`: Esto evita explícitamente el aceleramiento para esta solicitud, anulando todos los demás aceleradores.
+- `true`: Esto marca la solicitud como para ser acelerada.
+- `null`: Esto significa que este acelerador no se aplica. Cualquier otra salida será ignorada, con el mismo efecto que `null`.
+
+Los aceleradores se ejecutarán en TODAS las peticiones, y son responsables de averiguar si se aplican o no. Por ejemplo, considere el acelerador de correos de Flarum:
+
+```php
+use DateTime;
+use Flarum\Post\Post;
+
+function ($request) {
+ if (! use DateTime;
+use Flarum\Post\Post;
+
+function ($request) {
+ if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) {
+ return;
+ }
+
+ $actor = $request->getAttribute('actor');
+
+ if ($actor->can('postWithoutThrottle')) {
+ return false;
+ }
+
+ if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) {
+ return true;
+ }
+};
+```
+
+Los aceleradores pueden ser añadidos o eliminados a través del middleware `ThrottleApi` en `extend.php`. Por ejemplo:
+
+```php
+set('throttleAll', function () {
+ return false;
+ })
+ ->remove('bypassThrottlingAttribute'),
+ // Other extenders
+];
+```
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api.md
new file mode 100644
index 000000000..06d35f1cc
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api.md
@@ -0,0 +1,353 @@
+# API and Data Flow
+
+In the [previous article](models.md), we learned how Flarum uses models to interact with data. Here, we'll learn how to get that data from the database to the JSON-API to the frontend, and all the way back again.
+
+:::info
+
+To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md).
+
+:::
+
+## Ciclo de vida de las solicitudes de la API
+
+Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request:
+
+
+
+1. Se envía una solicitud HTTP a la API de Flarum. Normalmente, esto vendrá del frontend de Flarum, pero los programas externos también pueden interactuar con la API. La API de Flarum sigue en su mayoría la especificación [JSON:API](https://jsonapi.org/), por lo que, en consecuencia, las solicitudes deben seguir [dicha especificación](https://jsonapi.org/format/#fetching).
+2. La solicitud se ejecuta a través de [middleware](middleware.md), y se dirige al controlador adecuado. Puedes aprender más sobre los controladores en su conjunto en nuestra [documentación sobre rutas y contenido](routes.md). Asumiendo que la petición es a la API (que es el caso de esta sección), el controlador que maneja la petición será una subclase de `Flarum\Api\AbstractSerializeController`.
+3. Cualquier modificación realizada por las extensiones del controlador a través del extensor [`ApiController`] (#extending-api-controllers) se aplica. Esto podría suponer el cambio de sort, añadir includes, cambiar el serializador, etc.
+4. Se llama al método `$this->data()` del controlador, obteniendo algunos datos en bruto que deben ser devueltos al cliente. Típicamente, estos datos tomarán la forma de una colección o instancia del modelo de Laravel Eloquent, que ha sido recuperada de la base de datos. Dicho esto, los datos pueden ser cualquier cosa siempre que el serializador del controlador pueda procesarlos. Cada controlador es responsable de implementar su propio método `data`. Ten en cuenta que para las peticiones `PATCH`, `POST` y `DELETE`, `data` realizará la operación en cuestión, y devolverá la instancia del modelo modificado.
+5. Esos datos se ejecutan a través de cualquier callback de preserialización que las extensiones registren a través del extensor [`ApiController`](#extending-api-controllers).
+6. Los datos se pasan a través de un [serializador](#serializers), que los convierte del formato de base de datos del backend al formato JSON: API esperado por el frontend. También adjunta cualquier objeto relacionado, que se ejecuta a través de sus propios serializadores. Como explicaremos más adelante, las extensiones pueden [añadir / anular relaciones y atributos](#attributes-and-relationships) en el nivel de serialización.
+7. Los datos serializados se devuelven como una respuesta JSON al frontend.
+8. Si la solicitud se originó a través de la `Store` del frontend de Flarum, los datos devueltos (incluyendo cualquier objeto relacionado) serán almacenados como [modelos del frontend](#frontend-models) en el almacén del frontend.
+
+## API Endpoints
+
+We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints.
+
+As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are:
+
+- Listing instances of a model (possibly including searching/filtering)
+- Getting a single model instance
+- Creating a model instance
+- Updating a model instance
+- Deleting a single model instance
+
+We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender:
+
+```php
+ (new Extend\Routes('api'))
+ ->get('/tags', 'tags.index', ListTagsController::class)
+ ->get('/tags/{id}', 'tags.show', ShowTagController::class)
+ ->post('/tags', 'tags.create', CreateTagController::class)
+ ->patch('/tags/{id}', 'tags.update', UpdateTagController::class)
+ ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class)
+```
+
+:::caution
+
+Paths to API endpoints are not arbitrary! To support interactions with frontend models:
+
+- The path should either be `/prefix/{id}` for get/update/delete, or `/prefix` for list/create.
+- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`).
+- The methods must match the example above.
+
+Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique!
+
+:::
+
+The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources.
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically create your endpoint controllers:
+```bash
+$ flarum-cli make backend api-controller
+```
+
+:::
+
+### Listado de recursos
+
+For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`.
+
+```php
+use Flarum\Api\Controller\AbstractListController;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class ListTagsController extends AbstractListController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ return Tag::all();
+ }
+}
+```
+
+#### Paginación
+
+You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller:
+
+```php
+ // The number of records included by default.
+ public $limit = 20;
+
+ // The maximum number of records that can be requested.
+ public $maxLimit = 50;
+```
+
+You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods:
+
+```php
+$limit = $this->extractLimit($request);
+$offset = $this->extractOffset($request);
+
+return Tag::skip($offset)->take($limit);
+```
+
+To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method.
+
+#### Clasificación
+
+You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller:
+
+```php
+ // The default sort field and order to use.
+ public $sort = ['name' => 'asc'];
+
+ // The fields that are available to be sorted by.
+ public $sortFields = ['firstName', 'lastName'];
+```
+
+You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query:
+
+```php
+use Illuminate\Support\Str;
+
+// ...
+
+$sort = $this->extractSort($request);
+$query = Tag::query();
+
+foreach ($sort as $field => $order) {
+ $query->orderBy(Str::snake($field), $order);
+}
+
+return $query->get();
+```
+
+#### Search
+
+Read our [searching and filtering](search.md) guide for more information!
+
+### Mostrar un recurso
+
+For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers).
+
+```php
+use Flarum\Api\Controller\AbstractShowController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class ShowTagController extends AbstractShowController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ $id = Arr::get($request->getQueryParams(), 'id');
+
+ return Tag::findOrFail($id);
+ }
+}
+```
+
+### Creación de un recurso
+
+For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`:
+
+```php
+use Flarum\Api\Controller\AbstractCreateController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class CreateTagController extends AbstractCreateController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ $attributes = Arr::get($request->getParsedBody(), 'data.attributes');
+
+ return Tag::create([
+ 'name' => Arr::get($attributes, 'name')
+ ]);
+ }
+}
+```
+
+### Actualización de un recurso
+
+For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`.
+
+### Borrar un recurso
+
+For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response.
+
+```php
+use Flarum\Api\Controller\AbstractDeleteController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+class DeleteTagController extends AbstractDeleteController
+{
+ protected function delete(Request $request)
+ {
+ $id = Arr::get($request->getQueryParams(), 'id');
+
+ Tag::findOrFail($id)->delete();
+ }
+}
+```
+
+### ncluir Relaciones
+
+To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller:
+
+```php
+ // The relationships that are included by default.
+ public $include = ['user'];
+
+ // Other relationships that are available to be included.
+ public $optionalInclude = ['discussions'];
+```
+
+You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized:
+
+```php
+$relations = $this->extractInclude($request);
+
+return Tag::all()->load($relations);
+```
+
+### Extensión de los controladores de la API
+
+It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender
+
+```php
+use Flarum\Api\Event\WillGetData;
+use Flarum\Api\Controller\ListDiscussionsController;
+use Illuminate\Contracts\Events\Dispatcher;
+
+return [
+ (new Extend\ApiController(ListDiscussionsController::class))
+ ->setSerializer(MyDiscussionSerializer::class)
+ ->addInclude('user')
+ ->addOptionalInclude('posts')
+ ->setLimit(20)
+ ->setMaxLimit(50)
+ ->setSort(['name' => 'asc'])
+ ->addSortField('firstName')
+ ->prepareDataQuery(function ($controller) {
+ // Add custom logic here to modify the controller
+ // before data queries are executed.
+ })
+]
+```
+
+The `ApiController` extender can also be used to adjust data before serialization
+
+```php
+use Flarum\Api\Event\WillSerializeData;
+use Flarum\Api\Controller\ListDiscussionsController;
+use Illuminate\Contracts\Events\Dispatcher;
+
+return [
+ (new Extend\ApiController(ListDiscussionsController::class))
+ ->prepareDataForSerialization(function ($controller, $data, $request, $document) {
+ $data->load('myCustomRelation');
+ }),
+]
+```
+
+## Serializadores
+
+Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library.
+
+A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument:
+
+```php
+use Flarum\Api\Serializer\AbstractSerializer;
+use Flarum\Api\Serializer\UserSerializer;
+
+class DiscussionSerializer extends AbstractSerializer
+{
+ protected $type = 'discussions';
+
+ protected function getDefaultAttributes($discussion)
+ {
+ return [
+ 'title' => $discussion->title,
+ ];
+ }
+}
+```
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically create your serializer:
+```bash
+$ flarum-cli make backend api-serializer
+```
+
+:::
+
+### Atributos y relaciones
+
+You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources.
+
+```php
+ protected function user($discussion)
+ {
+ return $this->hasOne($discussion, UserSerializer::class);
+ }
+```
+
+### Extending Serializers
+
+To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender:
+
+```php
+use Flarum\Api\Serializer\UserSerializer;
+
+return [
+ (new Extend\ApiSerializer(UserSerializer::class))
+ // One attribute at a time
+ ->attribute('firstName', function ($serializer, $user, $attributes) {
+ return $user->first_name
+ })
+ // Multiple modifications at once, more complex logic
+ ->mutate(function($serializer, $user, $attributes) {
+ $attributes['someAttribute'] = $user->someAttribute;
+ if ($serializer->getActor()->can('administrate')) {
+ $attributes['someDate'] = $serializer->formatDate($user->some_date);
+ }
+
+ return $attributes;
+ })
+ // API relationships
+ ->hasOne('phone', PhoneSerializer::class)
+ ->hasMany('comments', CommentSerializer::class),
+]
+```
+
+### Non-Model Serializers and `ForumSerializer`
+
+Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`.
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/assets.md
new file mode 100644
index 000000000..16b401fc3
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/assets.md
@@ -0,0 +1,7 @@
+# Extension Assets
+
+Some extensions might want to include assets like images or JSON files in their source code (note that this is not the same as uploads, which would probably require a [filesystem disk](filesystem.md)).
+
+This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed.
+
+If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example.
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md
new file mode 100644
index 000000000..a8bf6f5ec
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md
@@ -0,0 +1,235 @@
+# Autorización
+
+Como todo framework, Flarum permite restringir ciertas acciones y contenidos a determinados usuarios. Hay dos sistemas paralelos para esto:
+
+- El proceso de autorización dicta si un usuario puede realizar una determinada acción.
+- El alcance de la visibilidad puede aplicarse a una consulta de la base de datos para restringir eficazmente los registros a los que los usuarios pueden acceder. This is documented in our [model visibility](model-visibility.md) article.
+
+## Proceso de Autorización
+
+El proceso de autorización se utiliza para comprobar si una persona está autorizada a realizar ciertas acciones. Por ejemplo, queremos comprobar si un usuario está autorizado antes de que:
+
+- Acceda al panel de control del administrador
+- Inicie un debate
+- Edite un mensaje
+- Actualice el perfil de otro usuario
+
+Cada uno de ellos está determinado por un criterio único: en algunos casos, un flag es suficiente; de lo contrario, podríamos necesitar una lógica personalizada.
+
+## Alcance de la visibilidad
+
+Las consultas de autorización se realizan con 3 parámetros, con la lógica contenida en [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/gate):
+
+1. El actor: el usuario que intenta realizar la acción
+2. La habilidad: una cadena que representa la acción que el actor está intentando
+3. Los argumentos: normalmente una instancia de un modelo de base de datos que es el objeto de la habilidad intentada, pero puede ser cualquier cosa.
+
+En primer lugar, pasamos la solicitud completa (los tres parámetros) por todas las [políticas](#policies) registradas por las extensiones y el núcleo. Las políticas son bloques de lógica proporcionados por el núcleo y las extensiones que determinan si el actor puede realizar la habilidad con los argumentos. Las políticas pueden devolver una de las siguientes cosas:
+
+- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`)
+- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`)
+- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`)
+- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`)
+
+Los resultados de las políticas se consideran en la prioridad `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. Por ejemplo, si una sola política devuelve `FORCE_DENY`, todas las demás políticas serán ignoradas. Si una política devuelve `DENY` y 10 políticas devuelven `ALLOW`, la solicitud será denegada. Esto permite tomar decisiones independientemente del orden en el que se arranquen las extensiones. Tenga en cuenta que las políticas son extremadamente poderosas: si el acceso es denegado en la etapa de políticas, eso anulará los permisos de grupo e incluso los privilegios de administrador.
+
+En segundo lugar, si todas las políticas devuelven null (o no devuelven nada), comprobamos si el usuario está en un grupo que tiene un permiso igual a la habilidad (nótese que tanto los permisos como las habilidades se representan como cadenas). Si es así, autorizamos la acción. Consulta nuestra [documentación sobre grupos y permisos](permissions.md) para obtener más información sobre los permisos.
+
+Luego, si el usuario está en el grupo de administradores, autorizaremos la acción.
+
+Finalmente, como hemos agotado todas las comprobaciones, asumiremos que el usuario no está autorizado y denegaremos la solicitud.
+
+## Autorización en el Frontend
+
+El sistema de autorización de Flarum es accesible a través de los métodos públicos de la clase `Flarum\User\User`. Los más importantes se enumeran a continuación; otros están documentados en nuestra [documentación de la API de PHP](https://api.docs.flarum.org/php/master/flarum/user/user).
+
+
+En este ejemplo, usaremos `$actor` como una instancia de `Flarum\User\User`, `'viewForum'` y `'reply'` como ejemplos de habilidades, y `$discussion` (instancia de `Flarum\Discussion\Discussion`) como argumento de ejemplo.
+
+```php
+// Comprueba si un usuario puede realizar una acción.
+// ADVERTENCIA: esto debe ser utilizado con precaución, ya que no
+// ejecuta el proceso de autorización, por lo que no tiene en cuenta las políticas.
+$canDoSomething = $actor->can('viewForum');
+
+// Comprueba si un usuario puede realizar una acción sobre un tema.
+// Sin embargo, es útil para implementar políticas personalizadas.
+$canDoSomething = $actor->can('reply', $discussion);
+
+// Lanza una PermissionDeniedException si un usuario no puede realizar una acción.
+$actpr->assertAdmin();
+
+// Comprueba si uno de los grupos del usuario tiene un permiso.
+$actor->assertCan('viewForum');
+$actor->assertCan('reply', $discussion);
+
+// Lanza una NotAuthenticatedException si el usuario no está conectado.
+$actor->assertRegistered();
+
+// Lanza una PermissionDeniedException si el usuario no es un administrador.
+$actorHasPermission = $actor->hasPermission(`viewForum`);
+```
+
+## Políticas personalizadas
+
+Las políticas nos permiten utilizar una lógica personalizada más allá de los simples grupos y permisos cuando se evalúa la autorización de una habilidad con un sujeto. Por ejemplo:
+
+- Queremos permitir a los usuarios editar los mensajes aunque no sean moderadores, pero sólo sus propios mensajes.
+- Dependiendo de la configuración, podríamos permitir a los usuarios renombrar sus propias discusiones indefinidamente, durante un corto período de tiempo después de la publicación, o no en absoluto.
+
+Como se describe [arriba](#how-it-works), en cualquier comprobación de autorización, consultamos todas las políticas registradas para el modelo del objetivo, o cualquier clase padre del modelo del objetivo. Si no se proporciona ningún objetivo, se aplicarán todas las políticas registradas como `global`.
+
+Entonces, ¿cómo se "comprueba" una política?
+
+En primer lugar, comprobamos si la clase política tiene un método con el mismo nombre que la habilidad que se está evaluando. Si es así, lo ejecutamos con el actor y el sujeto como parámetros. Si ese método devuelve un valor no nulo, devolvemos ese resultado. En caso contrario, continuamos con el siguiente paso (no necesariamente con la siguiente política).
+
+A continuación, comprobamos si la clase de política tiene un método llamado `can`. Si es así, lo ejecutamos con el actor, la habilidad y el sujeto, y devolvemos el resultado.
+
+Si `can` no existe o devuelve null, hemos terminado con esta política, y pasamos a la siguiente.
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically generate policies:
+```bash
+is_restricted) {
+ return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny();
+ }
+ }
+
+ /**
+ * @param User $actor
+ * @param Tag $tag
+ * @return bool|null
+ */
+ public function addToDiscussion(User $actor, Tag $tag)
+ {
+ return $this->startDiscussion($actor, $tag);
+ }
+}
+```
+
+:::
+
+### Cómo funciona
+
+Veamos algunos ejemplos de [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access/TagPolicy).
+
+```php
+whereIn('discussions.id', function ($query) use ($actor, $ability) {
+ return $query->select('discussion_id')
+ ->from('discussion_tag')
+ ->whereIn('tag_id', Tag::getIdsWhereCan($actor, 'discussion.'.$ability));
+ });
+ }
+}
+```
+
+También podemos tener políticas globales, que se ejecutan cuando `$user->can()` es llamado sin una instancia del modelo de destino. De nuevo desde Tags:
+
+```php
+settings = $settings;
+ }
+
+ /**
+ * @param Flarum\User\User $actor
+ * @param string $ability
+ * @return bool|void
+ */
+ public function can(User $actor, string $ability)
+ {
+ if (in_array($ability, ['viewForum', 'startDiscussion'])) {
+ $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags');
+ $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags');
+
+ if ($enoughPrimary && $enoughSecondary) {
+ return $this->allow();
+ } else {
+ return $this->deny();
+ }
+ }
+ }
+}
+```
+
+### Cómo usar la autorización
+
+¿Qué ocurre cuando llamamos a `whereVisibleTo`? Esta llamada es manejada por el sistema de alcance de visibilidad del modelo general de Flarum, que ejecuta la consulta a través de una secuencia de llamadas de retorno, que se llaman "scopers".
+
+```php
+use Flarum\Extend;
+use Flarum\Tags\Tag;
+use YourNamespace\Access;
+
+return [
+ // Otros extensores
+ (new Extend\Policy())
+ ->modelPolicy(Tag::class, Access\TagPolicy::class)
+ ->globalPolicy(Access\GlobalPolicy::class),
+ // Otros extensores
+];
+```
+
+## Frontend Authorization
+
+Comúnmente, querrás usar los resultados de la autorización en la lógica del frontend. Por ejemplo, si un usuario no tiene permiso para ver usuarios de búsqueda, no deberíamos enviar solicitudes a ese punto final. Y si un usuario no tiene permiso para editar usuarios, no deberíamos mostrar elementos del menú para ello.
+
+Como no podemos hacer comprobaciones de autorización en el frontend, tenemos que realizarlas en el backend, y adjuntarlas a la serialización de los datos que estamos enviando. Los permisos globales (`viewForum`, `viewUserList`) pueden incluirse en el `ForumSerializer`, pero para la autorización específica de un objeto, podemos querer incluirlos con el objeto sujeto. Por ejemplo, cuando devolvemos listas de discusiones, comprobamos si el usuario puede responder, renombrar, editar y borrar, y almacenamos esos datos en el modelo de discusión del frontend. Entonces es accesible a través de `discussion.canReply()` o `discussion.canEdit()`, pero no hay nada mágico ahí: es sólo otro atributo enviado por el serializador.
+
+Hay dos tipos de scopers:
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md
new file mode 100644
index 000000000..90ea57107
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md
@@ -0,0 +1,215 @@
+# Eventos del Backend
+
+A menudo, una extensión querrá reaccionar a algunos eventos que ocurren en otra parte de Flarum. Por ejemplo, podríamos querer incrementar un contador cuando se publica una nueva discusión, enviar un email de bienvenida cuando un usuario se conecta por primera vez, o añadir etiquetas a una discusión antes de guardarla en la base de datos. Estos eventos se conocen como **eventos de dominio**, y se transmiten a todo el framework a través del [sistema de eventos de Laravel](https://laravel.com/docs/6.x/events).
+
+Para obtener una lista completa de los eventos del backend, consulte nuestra [documentación de la API](https://api.docs.flarum.org/php/master/search.html?search=Event). Las clases de eventos del dominio están organizadas por espacio de nombres, normalmente `Flarum\TYPE\Event`.
+
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+You can use the CLI to automatically generate event listeners:
+```bash
+use Flarum\Extend;
+use Flarum\Post\Event\Deleted;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+
+return [
+ (new Extend\Event)
+ ->listen(Deleted::class, function($event) {
+ // haz algo aquí
+ })
+ ->listen(Deleted::class, PostDeletedListener::class)
+];
+
+
+class PostDeletedListener
+{
+ protected $translator;
+
+ public function __construct(TranslatorInterface $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public function handle(Deleted $event)
+ {
+ // Su lógica aquí
+ }
+}
+```
+
+:::
+
+## Escuchar eventos
+
+Puedes adjuntar un oyente a un evento utilizando el [extensor] [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event)(start.md#extenders):
+
+```php
+use Flarum\Post\Event\Deleted;
+use Illuminate\Contracts\Events\Dispatcher;
+
+
+class SomeClass
+{
+ /**
+ * @var Dispatcher
+ */
+ protected $events;
+
+ /**
+ * @param Dispatcher $events
+ */
+ public function __construct(Dispatcher $events)
+ {
+ $this->events = $events;
+ }
+
+ public function someMethod()
+ {
+ // Lógica
+ $this->events->dispatch(
+ new Deleted($somePost, $someActor)
+ );
+ // Más lógica
+ }
+}
+```
+```php
+class PostDeletedListener
+{
+ protected $translator;
+
+ public function __construct(TranslatorInterface $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public function handle(Deleted $event)
+ {
+ // Your logic here
+ }
+}
+```
+
+Como se muestra arriba, se puede utilizar una clase listener en lugar de un callback. Esto le permite [inyectar dependencias](https://laravel.com/docs/6.x/container) en su clase listener a través de los parámetros del constructor. En este ejemplo resolvemos una instancia de traductor, pero podemos inyectar cualquier cosa que queramos/necesitemos.
+
+You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts:
+
+```php
+use Flarum\Extend;
+use Flarum\Post\Event\Deleted;
+use Flarum\Post\Event\Saving;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+
+return [
+ (new Extend\Event)
+ ->subscribe(PostEventSubscriber::class),
+];
+```
+```php
+class PostEventSubscriber
+{
+ protected $translator;
+
+ public function __construct(TranslatorInterface $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public function subscribe($events)
+ {
+ $events->listen(Deleted::class, [$this, 'handleDeleted']);
+ $events->listen(Saving::class, [$this, 'handleSaving']);
+ }
+
+ public function handleDeleted(Deleted $event)
+ {
+ // Your logic here
+ }
+
+ public function handleSaving(Saving $event)
+ {
+ // Your logic here
+ }
+}
+```
+
+## Dispatching de eventos
+
+Despachar eventos es muy sencillo. Todo lo que necesitas hacer es inyectar `Illuminate\Contracts\Events\Dispatcher` en tu clase, y luego llamar a su método `dispatch`. Por ejemplo:
+
+```php
+use Flarum\Post\Event\Deleted;
+use Illuminate\Contracts\Events\Dispatcher;
+
+
+class SomeClass
+{
+ /**
+ * @var Dispatcher
+ */
+ protected $events;
+
+ /**
+ * @param Dispatcher $events
+ */
+ public function __construct(Dispatcher $events)
+ {
+ $this->events = $events;
+ }
+
+ public function someMethod()
+ {
+ // Logic
+ $this->events->dispatch(
+ new Deleted($somePost, $someActor)
+ );
+ // More Logic
+ }
+}
+```
+
+## Eventos personalizados
+
+Como desarrollador de extensiones puedes definir tus propios eventos para permitirte a ti mismo (o a otras extensiones) reaccionar a eventos en tu extensión. Los eventos son generalmente instancias de clases simples (no es necesario extender nada). Cuando definas un nuevo evento, normalmente querrás usar propiedades públicas, y quizás algunos métodos para la comodidad de los usuarios. Por ejemplo, si echamos un vistazo a `Flarum\Post\Event\Deleted`, es sólo una envoltura de algunos datos:
+
+```php
+post = $post;
+ $this->actor = $actor;
+ }
+}
+```
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/cli.md
new file mode 100644
index 000000000..ab88b1142
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/cli.md
@@ -0,0 +1,15 @@
+# Desarrolladores explicando su flujo de trabajo para el desarrollo de extensiones
+
+The Flarum development ecosystem is oriented around many small, modules, interacting extensions. This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions.
+
+We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle.
+
+Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10).
+
+See the [package's readme](https://github.com/flarum/cli#readme) for information on:
+
+- Instalación
+- Usage
+- Upgrading
+- Available commands
+- Some implementation details, if you're interested
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/console.md
new file mode 100644
index 000000000..d989d2b02
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/console.md
@@ -0,0 +1,79 @@
+# Consola
+
+Flarum permite a los desarrolladores de extensiones añadir comandos de consola personalizados además de los [predeterminados](../console.md) proporcionados por el núcleo de flarum.
+
+Todo el desarrollo de comandos de consola se realiza en el backend usando PHP. Para crear un comando de consola personalizado, necesitará crear una clase que extienda `Flarum\Console\AbstractCommand`.
+
+```php
+use Flarum\Console\AbstractCommand;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+
+class YourCommand implements AbstractCommand {
+ protected function configure()
+ {
+ $this
+ ->setName('YOUR COMMAND NAME')
+ ->setDescription('YOUR COMMAND DESCRIPTION');
+ }
+ protected function fire()
+ {
+ // Su lógica aquí
+ }
+}
+ }
+}
+```
+
+:::info [Flarum CLI](https://github.com/flarum/cli)
+
+:::tip Comandos Programados
+```bash
+use Flarum\Extend;
+use YourNamespace\Console\CustomCommand;
+
+return [
+ // Otros extensores
+ (new Extend\Console())->command(CustomCommand::class)
+ // Otros extensores
+];
+```
+
+:::
+
+## Registro de los comandos de la consola
+
+To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file:
+
+```php
+use Flarum\Extend;
+use YourNamespace\Console\CustomCommand;
+
+return [
+ // Other extenders
+ (new Extend\Console())->command(CustomCommand::class)
+ // Other extenders
+];
+```
+
+## Scheduled Commands
+
+La [fof/console library](https://github.com/FriendsOfFlarum/console) le permite programar comandos para que se ejecuten en un intervalo regular.
+
+
+```php
+use Flarum\Extend;
+use YourNamespace\Console\CustomCommand;
+use Illuminate\Console\Scheduling\Event;
+
+return [
+ // Other extenders
+ (new Extend\Console())->schedule('cache:clear', function (Event $event) {
+ $event->everyMinute();
+ }, ['Arg1', '--option1', '--option2']),
+ // Other extenders
+];
+```
+
+In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information.
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/data.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/data.md
new file mode 100644
index 000000000..88de40415
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/data.md
@@ -0,0 +1,562 @@
+# Trabajar con datos
+
+Los datos son la base de cualquier foro, así que vas a tener que jugar bien con ellos si quieres que tu extensión haga algo útil. Este documento repasa cómo fluyen los datos en Flarum, desde la base de datos hasta el JSON-API y el frontend, y todo el camino de vuelta.
+
+Flarum utiliza el componente de base de datos de [Laravel](https://laravel.com/docs/database). Debes familiarizarte con él antes de continuar, ya que se asume como conocimiento previo en la siguiente documentación.
+
+## Ciclo de vida de las solicitudes de la API
+
+Antes de entrar en detalles sobre cómo ampliar la API de datos de Flarum, vale la pena pensar en el ciclo de vida de una solicitud de datos típica:
+
+1. Se envía una solicitud HTTP a la API de Flarum. Normalmente, esto vendrá del frontend de Flarum, pero los programas externos también pueden interactuar con la API. La API de Flarum sigue en su mayoría la especificación [JSON:API](https://jsonapi.org/), por lo que, en consecuencia, las solicitudes deben seguir [dicha especificación](https://jsonapi.org/format/#fetching).
+2. La solicitud se ejecuta a través de [middleware](middleware.md), y se dirige al controlador adecuado. Puedes aprender más sobre los controladores en su conjunto en nuestra [documentación sobre rutas y contenido](routes.md). Asumiendo que la petición es a la API (que es el caso de esta sección), el controlador que maneja la petición será una subclase de `Flarum\Api\AbstractSerializeController`.
+3. Cualquier modificación realizada por las extensiones del controlador a través del extensor [`ApiController`] (#extending-api-controllers) se aplica. Esto podría suponer el cambio de sort, añadir includes, cambiar el serializador, etc.
+4. Se llama al método `$this->data()` del controlador, obteniendo algunos datos en bruto que deben ser devueltos al cliente. Típicamente, estos datos tomarán la forma de una colección o instancia del modelo de Laravel Eloquent, que ha sido recuperada de la base de datos. Dicho esto, los datos pueden ser cualquier cosa siempre que el serializador del controlador pueda procesarlos. Cada controlador es responsable de implementar su propio método `data`. Ten en cuenta que para las peticiones `PATCH`, `POST` y `DELETE`, `data` realizará la operación en cuestión, y devolverá la instancia del modelo modificado.
+5. Esos datos se ejecutan a través de cualquier callback de preserialización que las extensiones registren a través del extensor [`ApiController`](#extending-api-controllers).
+6. Los datos se pasan a través de un [serializador](#serializers), que los convierte del formato de base de datos del backend al formato JSON:API esperado por el frontend. También adjunta cualquier objeto relacionado, que se ejecuta a través de sus propios serializadores. Como explicaremos más adelante, las extensiones pueden [añadir / anular relaciones y atributos](#attributes-and-relationships) en el nivel de serialización.
+7. Los datos serializados se devuelven como una respuesta JSON al frontend.
+8. Si la solicitud se originó a través de la `Store` del frontend de Flarum, los datos devueltos (incluyendo cualquier objeto relacionado) serán almacenados como [modelos del frontend](#frontend-models) en el almacén del frontend.
+
+## Migraciones
+
+Si queremos utilizar un modelo personalizado, o añadir atributos a uno existente, tendremos que modificar la base de datos para añadir tablas / columnas. Esto lo hacemos a través de las migraciones.
+
+Las migraciones son como un control de versiones para su base de datos, permitiéndole modificar fácilmente el esquema de la base de datos de Flarum de forma segura. Las migraciones de Flarum son muy similares a las de [Laravel](https://laravel.com/docs/migrations), aunque hay algunas diferencias.
+
+Las migraciones viven dentro de una carpeta convenientemente llamada `migrations` en el directorio de su extensión. Las migraciones deben ser nombradas en el formato `YYY_MM_DD_HHMMSS_snake_case_description` para que sean listadas y ejecutadas en orden de creación.
+
+### Estructura de la migración
+
+En Flarum, los archivos de migración deben **devolver un array** con dos funciones: `up` y `down`. La función `up` se utiliza para añadir nuevas tablas, columnas o índices a tu base de datos, mientras que la función `down` debe revertir estas operaciones. Estas funciones reciben una instancia del [Laravel schema builder](https://laravel.com/docs/6.x/migrations#creating-tables) que puedes usar para alterar el esquema de la base de datos:
+
+```php
+ function (Builder $schema) {
+ // up migration
+ },
+ 'down' => function (Builder $schema) {
+ // down migration
+ }
+];
+```
+
+Para tareas comunes como la creación de una tabla, o la adición de columnas a una tabla existente, Flarum proporciona algunos ayudantes que construyen esta matriz para usted, y se encargan de escribir la lógica de migración `down` mientras están en ello. Están disponibles como métodos estáticos en la clase `Flarum\Database\Migration`.
+
+### Ciclo de vida de las migraciones
+
+Las migraciones se aplican cuando la extensión se habilita por primera vez o cuando está habilitada y hay algunas migraciones pendientes. Las migraciones ejecutadas se registran en la base de datos, y cuando se encuentran algunas en la carpeta de migraciones de una extensión que no están registradas como completadas todavía, se ejecutarán.
+
+Las migraciones también pueden aplicarse manualmente con `php flarum migrate`, que también es necesario para actualizar las migraciones de una extensión ya habilitada. Para deshacer los cambios aplicados por las migraciones, es necesario hacer clic en "Desinstalar" junto a una extensión en la interfaz de administración, o utilizar el comando `php flarum migrate:reset`. No se puede romper nada ejecutando `php flarum migrate` de nuevo si ya has migrado - las migraciones ejecutadas no se ejecutarán de nuevo.
+
+Actualmente no hay ganchos a nivel de compositor para gestionar las migraciones en absoluto (es decir, actualizar una extensión con `composer update` no ejecutará sus migraciones pendientes).
+
+### Creación de tablas
+
+Para crear una tabla, utilice el ayudante `Migration::createTable`. El ayudante `createTable` acepta dos argumentos. El primero es el nombre de la tabla, mientras que el segundo es un `Closure` que recibe un objeto `Blueprint` que puede ser utilizado para definir la nueva tabla:
+
+```php
+use Flarum\Database\Migration;
+use Illuminate\Database\Schema\Blueprint;
+
+return Migration::createTable('users', function (Blueprint $table) {
+ $table->increments('id');
+});
+```
+
+Al crear la tabla, puede utilizar cualquiera de los [métodos de columna](https://laravel.com/docs/6.x/migrations#creating-columns) del constructor de esquemas para definir las columnas de la tabla.
+
+### Renombrar Tablas
+
+Para renombrar una tabla de la base de datos existente, utilice el ayudante `Migration::renameTable`:
+
+```php
+return Migration::renameTable($from, $to);
+```
+
+### Crear/eliminar columnas
+
+Para añadir columnas a una tabla existente, utilice el ayudante `Migration::addColumns`. El ayudante `addColumns` acepta dos argumentos. El primero es el nombre de la tabla. El segundo es un array de definiciones de columnas, cuya clave es el nombre de la columna. El valor de cada elemento es un array con las definiciones de las columnas, tal y como lo entiende el método `Illuminate\Database\Schema\Blueprint::addColumn()` de Laravel. El primer valor es el tipo de columna, y cualquier otro valor clave se pasa a través de `addColumn`.
+
+```php
+return Migration::addColumns('users', [
+ 'email' => ['string', 'nullable' => true],
+ 'discussion_count' => ['integer', 'unsigned' => true]
+]);
+```
+
+Para eliminar columnas de una tabla existente, utilice el ayudante `Migration::dropColumns`, que acepta los mismos argumentos que el ayudante `addColumns`. Al igual que cuando se eliminan tablas, se deben especificar las definiciones completas de las columnas para que la migración se pueda revertir limpiamente.
+
+### Renombrar columnas
+
+Para cambiar el nombre de las columnas, utilice el ayudante `Migration::renameColumns`. El ayudante `renameColumns` acepta dos argumentos. El primero es el nombre de la tabla, mientras que el segundo es un array de nombres de columnas a renombrar:
+
+```php
+return Migration::renameColumns('users', ['from' => 'to']);
+```
+
+### Migraciones de Datos (Avanzado)
+
+Una migración no tiene por qué cambiar la estructura de la base de datos: puedes utilizar una migración para insertar, actualizar o eliminar filas en una tabla. Por ejemplo, puedes utilizar las migraciones para asignar [permisos personalizados](permissions.md) a otros grupos que no sean el de Administrador, o proporcionar algunos datos iniciales para un modelo personalizado de Eloquent. Dado que tienes acceso al [Eloquent Schema Builder](https://laravel.com/docs/6.x/migrations#creating-tables), todo es posible (aunque, por supuesto, debes ser extremadamente cauteloso y probar tu extensión extensamente).
+
+Las migraciones de datos son la forma recomendada de especificar la configuración y los permisos por defecto.
+
+## Modelos del backend
+
+Con todas tus nuevas tablas y columnas de la base de datos, vas a querer una forma de acceder a los datos tanto en el backend como en el frontend. En el backend es bastante sencillo - sólo necesitas estar familiarizado con [Eloquent](https://laravel.com/docs/6.x/eloquent).
+
+### Añadir nuevos modelos
+
+Si has añadido una nueva tabla, tendrás que crear un nuevo modelo para ella. En lugar de extender la clase `Model` de Eloquent directamente, deberías extender `Flarum\Database\AbstractModel` que proporciona un poco de funcionalidad extra para permitir que tus modelos sean extendidos por otras extensiones.
+
+
+
+### Relaciones
+
+También puedes añadir [relaciones](https://laravel.com/docs/6.x/eloquent-relationships) a los modelos existentes utilizando los métodos `hasOne`, `belongsTo`, `hasMany`, `belongsToMany` y `relationship` del extensor `Model`. El primer argumento es el nombre de la relación; el resto de los argumentos se pasan al método equivalente en el modelo, por lo que se puede especificar el nombre del modelo relacionado y, opcionalmente, anular los nombres de las tablas y las claves:
+
+```php
+ new Extend\Model(User::class)
+ ->hasOne('phone', 'App\Phone', 'foreign_key', 'local_key')
+ ->belongsTo('country', 'App\Country', 'foreign_key', 'other_key')
+ ->hasMany('comment', 'App\Comment', 'foreign_key', 'local_key')
+ ->belongsToMany('role', 'App\Role', 'role_user', 'user_id', 'role_id')
+```
+
+Estos 4 métodos deberían cubrir la mayoría de las relaciones, pero a veces se necesita una personalización más fina (por ejemplo, `morphMany`, `morphToMany` y `morphedByMany`). Cualquier relación válida de Eloquent es soportada por el método `relationship`:
+
+```php
+ new Extend\Model(User::class)
+ ->relationship('mobile', 'App\Phone', function ($user) {
+ // Devuelve aquí cualquier relación Eloquent.
+ return $user->belongsToMany(Discussion::class, 'recipients')
+ ->withTimestamps()
+ ->wherePivot('removed_at', null);
+ })
+```
+
+## Serializadores
+
+El siguiente paso es exponer tus nuevos datos en el JSON:API de Flarum para que puedan ser consumidos por el frontend. Debes familiarizarte con la [especificación JSON:API](https://jsonapi.org/format/). La capa JSON:API de Flarum se alimenta de la biblioteca [tobscure/json-api](https://github.com/tobscure/json-api).
+
+Los recursos JSON:API son definidos por **serializadores**. Para definir un nuevo tipo de recurso, crea una nueva clase de serializador que extienda `FlarumApi\Serializer\AbstractSerializer`. Debe especificar un recurso `$type` e implementar el método `getDefaultAttributes` que acepta la instancia del modelo como único argumento:
+
+```php
+use Flarum\Api\Serializer\AbstractSerializer;
+use Flarum\Api\Serializer\UserSerializer;
+
+class DiscussionSerializer extends AbstractSerializer
+{
+ protected $type = 'discussions';
+
+ protected function getDefaultAttributes($discussion)
+ {
+ return [
+ 'title' => $discussion->title,
+ ];
+ }
+}
+```
+
+### Atributos y relaciones
+
+También puedes especificar relaciones para tu recurso. Simplemente crea un nuevo método con el mismo nombre que la relación en tu modelo, y devuelve una llamada a `hasOne` o `hasMany` dependiendo de la naturaleza de la relación. Debes pasar la instancia del modelo y el nombre del serializador a utilizar para los recursos relacionados.
+
+```php
+ protected function user($discussion)
+ {
+ return $this->hasOne($discussion, UserSerializer::class);
+ }
+```
+
+Para añadir **atributos** y **relaciones** a un tipo de recurso existente, utilice el extensor `ApiSerializer`:
+
+```php
+use Flarum\Api\Serializer\UserSerializer;
+
+return [
+ (new Extend\ApiSerializer(UserSerializer::class))
+ // Un atributo a la vez
+ ->attribute('firstName', function ($serializer, $user, $attributes) {
+ return $user->first_name
+ })
+ // Múltiples modificaciones a la vez, lógica más compleja
+ ->mutate(function($serializer, $user, $attributes) {
+ $attributes['someAttribute'] = $user->someAttribute;
+ if ($serializer->getActor()->can('administrate')) {
+ $attributes['someDate'] = $serializer->formatDate($user->some_date);
+ }
+
+ return $attributes;
+ })
+ // Relaciones de la API
+ ->hasOne('phone', PhoneSerializer::class)
+ ->hasMany('comments', CommentSerializer::class),
+]
+```
+
+## API Endpoints
+
+Una vez que hayas definido tus recursos en los serializadores, necesitarás exponerlos como puntos finales de la API añadiendo rutas y controladores.
+
+Siguiendo las convenciones de JSON-API, puedes añadir cinco rutas estándar para tu tipo de recurso utilizando el extensor `Routes`:
+
+```php
+ (new Extend\Routes('api'))
+ ->get('/tags', 'tags.index', ListTagsController::class)
+ ->get('/tags/{id}', 'tags.show', ShowTagController::class)
+ ->post('/tags', 'tags.create', CreateTagController::class)
+ ->patch('/tags/{id}', 'tags.update', UpdateTagController::class)
+ ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class)
+```
+
+El espacio de nombres `Flarum\Api\Controller` contiene una serie de clases abstractas de controladores que puedes extender para implementar fácilmente tus recursos JSON-API.
+
+### Listado de recursos
+
+Para el controlador que enumera su recurso, extienda la clase `FlarumApi\Controller\AbstractListController`. Como mínimo, necesitas especificar el `$serializer` que quieres usar para serializar tus modelos, e implementar un método `data` para devolver una colección de modelos. El método `data` acepta el objeto `Request` y el `Document` tobscure/json-api.
+
+```php
+use Flarum\Api\Controller\AbstractListController;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class ListTagsController extends AbstractListController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ return Tag::all();
+ }
+}
+```
+
+### Mostrar un recurso
+
+Para el controlador que muestra un solo recurso, extienda la clase `Flarum\Api\Controller\AbstractShowController`. Al igual que para el controlador de la lista, es necesario especificar el `$serializer` que desea utilizar para serializar sus modelos, e implementar un método `data` para devolver un solo modelo:
+
+```php
+use Flarum\Api\Controller\AbstractShowController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class ShowTagController extends AbstractShowController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ $id = Arr::get($request->getQueryParams(), 'id');
+
+ return Tag::findOrFail($id);
+ }
+}
+```
+
+### Creación de un recurso
+
+Para el controlador que crea un recurso, extienda la clase `Flarum\Api\Controller\AbstractCreateController`. Esto es lo mismo que el controlador de mostrar, excepto que el código de estado de la respuesta se establecerá automáticamente a `201 Created`. Puede acceder al cuerpo del documento JSON:API entrante a través de `$request->getParsedBody()`:
+
+```php
+use Flarum\Api\Controller\AbstractCreateController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Tobscure\JsonApi\Document;
+
+class CreateTagController extends AbstractCreateController
+{
+ public $serializer = TagSerializer::class;
+
+ protected function data(Request $request, Document $document)
+ {
+ $attributes = Arr::get($request->getParsedBody(), 'data.attributes');
+
+ return Tag::create([
+ 'name' => Arr::get($attributes, 'name')
+ ]);
+ }
+}
+```
+
+### Actualización de un recurso
+
+Para el controlador que actualiza un recurso, extienda la clase `Flarum\Api\Controller\AbstractShowController`. Al igual que para el controlador de creación, puedes acceder al cuerpo del documento JSON:API entrante a través de `$request->getParsedBody()`.
+
+### Borrar un recurso
+
+Para el controlador que borra un recurso, extienda la clase `Flarum\Api\Controller\AbstractDeleteController`. Sólo necesitas implementar un método `delete` que ejecute el borrado. El controlador devolverá automáticamente una respuesta vacía `204 No Content`.
+
+```php
+use Flarum\Api\Controller\AbstractDeleteController;
+use Illuminate\Support\Arr;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+class DeleteTagController extends AbstractDeleteController
+{
+ protected function delete(Request $request)
+ {
+ $id = Arr::get($request->getQueryParams(), 'id');
+
+ Tag::findOrFail($id)->delete();
+ }
+}
+```
+
+### ncluir Relaciones
+
+Para incluir las relaciones al **enumerar**, **mostrar** o **crear** su recurso, especifíquelas en las propiedades `$include` y `$optionalInclude` de su controlador:
+
+```php
+ // Las relaciones que se incluyen por defecto.
+ public $include = ['user'];
+
+ // Otras relaciones que están disponibles para ser incluidas.
+ public $optionalInclude = ['discussions'];
+```
+
+A continuación, puede obtener una lista de relaciones incluidas utilizando el método `extractInclude`. Esto se puede utilizar para cargar con avidez las relaciones en sus modelos antes de que se serialicen:
+
+```php
+$relations = $this->extractInclude($request);
+
+return Tag::all()->load($relations);
+```
+
+### Paginación
+
+Puede permitir que el número de recursos que se **liste** sea personalizado especificando las propiedades `limit` y `maxLimit` en su controlador:
+
+```php
+ // El número de registros incluidos por defecto.
+ public $limit = 20;
+
+ // El número máximo de registros que se pueden solicitar.
+ public $maxLimit = 50;
+```
+
+A continuación, puede extraer la información de paginación de la solicitud utilizando los métodos `extractLimit` y `extractOffset`:
+
+```php
+$limit = $this->extractLimit($request);
+$offset = $this->extractOffset($request);
+
+return Tag::skip($offset)->take($limit);
+```
+
+Para añadir enlaces de paginación al documento JSON:API, utilice el método [`Document::addPaginationLinks`](https://github.com/tobscure/json-api#meta--links).
+
+### Clasificación
+
+Puede permitir que se personalice el orden de clasificación de los recursos que se **listen** especificando las propiedades `sort` y `sortField` en su controlador:
+
+```php
+ // El campo de clasificación por defecto y el orden a utilizar.
+ public $sort = ['name' => 'asc'];
+
+ // Los campos que están disponibles para ser ordenados.
+ public $sortFields = ['firstName', 'lastName'];
+```
+
+A continuación, puede extraer la información de ordenación de la solicitud utilizando el método `extractSort`. Esto devolverá un array de criterios de ordenación que puedes aplicar a tu consulta:
+
+```php
+$sort = $this->extractSort($request);
+$query = Tag::query();
+
+foreach ($sort as $field => $order) {
+ $query->orderBy(snake_case($field), $order);
+}
+
+return $query->get();
+```
+
+### Extensión de los controladores de la API
+
+También es posible personalizar todas estas opciones en controladores de API _existentes_ mediante el extensor `ApiController`.
+
+```php
+use Flarum\Api\Event\WillGetData;
+use Flarum\Api\Controller\ListDiscussionsController;
+use Illuminate\Contracts\Events\Dispatcher;
+
+return [
+ (new Extend\ApiController(ListDiscussionsController::class))
+ ->setSerializer(MyDiscussionSerializer::class)
+ ->addInclude('user')
+ ->addOptionalInclude('posts')
+ ->setLimit(20)
+ ->setMaxLimit(50)
+ ->setSort(['name' => 'asc'])
+ ->addSortField('firstName')
+ ->prepareDataQuery(function ($controller) {
+ // Añade aquí la lógica personalizada para modificar el controlador
+ // antes de que se ejecuten las consultas de datos.
+ })
+]
+```
+
+El extensor `ApiController` también puede utilizarse para ajustar los datos antes de la serialización
+
+```php
+use Flarum\Api\Event\WillSerializeData;
+use Flarum\Api\Controller\ListDiscussionsController;
+use Illuminate\Contracts\Events\Dispatcher;
+
+return [
+ (new Extend\ApiController(ListDiscussionsController::class))
+ ->prepareDataForSerialization(function ($controller, $data, $request, $document) {
+ $data->load('myCustomRelation');
+ }),
+]
+```
+
+## Modelos Frontend
+
+Ahora que has expuesto tus datos en el JSON:API de Flarum, es finalmente el momento de darles vida y consumirlos en el frontend.
+
+### Obtención de datos
+
+El frontend de Flarum contiene un `store` de datos local que proporciona una interfaz para interactuar con el JSON:API. Puedes recuperar recursos de la API usando el método `find`, que siempre devuelve una promesa:
+
+
+```js
+// GET /api/discussions?sort=createdAt
+app.store.find('discussions', {sort: 'createdAt'}).then(console.log);
+
+// GET /api/discussions/123
+app.store.find('discussions', 123).then(console.log);
+```
+
+Una vez cargados los recursos, se guardarán en la caché del almacén para que puedas acceder a ellos de nuevo sin tener que recurrir a la API utilizando los métodos `all` y `getById`:
+
+```js
+const discussions = app.store.all('discussions');
+const discussion = app.store.getById('discussions', 123);
+```
+
+El almacén envuelve los datos brutos de los recursos de la API en objetos modelo que facilitan el trabajo. Se puede acceder a los atributos y relaciones a través de métodos de instancia predefinidos:
+
+```js
+const id = discussion.id();
+const title = discussion.title();
+const posts = discussion.posts(); // array de modelos Post
+```
+
+Puede obtener más información sobre el almacén en nuestra [documentación de la API] (https://api.docs.flarum.org/js/master/class/src/common/store.js~store).
+
+### Añadir nuevos modelos
+
+Si has añadido un nuevo tipo de recurso, tendrás que definir un nuevo modelo para él. Los modelos deben extender la clase `Model` y redefinir los atributos y relaciones del recurso:
+
+
+```js
+import Model from 'flarum/Model';
+
+export default class Tag extends Model {
+ title = Model.attribute('title');
+ createdAt = Model.attribute('createdAt', Model.transformDate);
+ parent = Model.hasOne('parent');
+ discussions = Model.hasMany('discussions');
+}
+```
+
+A continuación, debe registrar su nuevo modelo en el almacén:
+
+```js
+app.store.models.tags = Tag;
+```
+
+
+
+### Extender los modelos
+
+Para añadir atributos y relaciones a los modelos existentes, modifique el prototipo de la clase del modelo:
+
+```js
+Discussion.prototype.user = Model.hasOne('user');
+Discussion.prototype.posts = Model.hasMany('posts');
+Discussion.prototype.slug = Model.attribute('slug');
+```
+
+
+
+### Ahorro de recursos
+
+Para enviar datos a través de la API, llame al método `save` en una instancia del modelo. Este método devuelve una Promise que se resuelve con la misma instancia del modelo:
+
+```js
+discussion.save({ title: 'Hello, world!' }).then(console.log);
+```
+
+También puede guardar las relaciones pasándolas en una clave `relationships`. Para las relaciones has-one, pasa una única instancia del modelo. Para las relaciones has-muchos, pasa una matriz de instancias del modelo.
+
+```js
+user.save({
+ relationships: {
+ groups: [
+ store.getById('groups', 1),
+ store.getById('groups', 2)
+ ]
+ }
+})
+```
+
+### Creación de nuevos recursos
+
+Para crear un nuevo recurso, cree una nueva instancia del modelo para el tipo de recurso utilizando el método `createRecord` de la tienda, y luego `save`:
+
+```js
+const discussion = app.store.createRecord('discussions');
+
+discussion.save({ title: 'Hello, world!' }).then(console.log);
+```
+
+### Borrar recursos
+
+Para eliminar un recurso, llame al método `delete` en una instancia del modelo. Este método devuelve una Promise:
+
+```js
+discussion.delete().then(done);
+```
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md
new file mode 100644
index 000000000..dc5fe6845
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md
@@ -0,0 +1,40 @@
+# Distribución
+
+Has escrito una gran extensión y ahora quieres que todo el mundo pueda usarla. Este documento te llevará a través del proceso de distribución, desde la creación de un repositorio Git para tu extensión, hasta su publicación en Packagist.
+
+## Configurar Git
+
+Lo primero que tienes que hacer es configurar un sistema de control de versiones (VCS). El VCS más popular es [Git](https://git-scm.com/). En esta guía usaremos Git, así que asegúrate de tenerlo [instalado](https://git-scm.com/downloads) antes de continuar. Si no tienes muchos conocimientos sobre Git, puedes consultar [estos recursos de aprendizaje](https://try.github.io/).
+
+Después de haber instalado Git, necesitarás inicializar tu repositorio. Puedes usar `git init` en la línea de comandos si te sientes cómodo, o usar una herramienta GUI como [SourceTree](https://www.sourcetreeapp.com/) o [GitKraken](https://www.gitkraken.com/).
+
+A continuación, necesitarás una cuenta en un servidor de alojamiento de Git, siendo los más populares [GitHub](https://github.com) y [GitLab](https://gitlab.com). Estos te indicarán cómo conectar tu repositorio local con el repositorio "remoto" en línea.
+
+## Etiquetar una versión
+
+Como vas a publicar esta extensión, querrás asegurarte de que la información está actualizada. Tómese un minuto para revisar `composer.json` y asegurarse de que el nombre del paquete, la descripción y la información de la extensión Flarum son correctos. Se recomienda tener un archivo `README.md` en su repositorio para explicar qué es la extensión, así que cree uno si aún no lo ha hecho.
+
+Cuando esté listo para publicar, envíe los archivos de su extensión al repositorio y etiquete su primera versión:
+
+```bash
+git tag v0.1.0
+git push && git push --tags
+```
+
+## Publicar en Packagist
+
+Los paquetes de Composer se publican en un repositorio de Composer, normalmente [Packagist](https://packagist.org/). Necesitarás una cuenta para proceder.
+
+Si esta es la primera versión que publicas de tu extensión, tendrás que [enviar tu paquete](https://packagist.org/packages/submit) utilizando la URL de su repositorio público. Si tu extensión se encuentra en GitHub, esta URL será algo así como `https://github.com/AUTHOR/NAME.git`.
+
+### Future Releases
+
+You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server.
+
+## Promover su extensión
+
+Lo más probable es que quieras crear una discusión en la Comunidad Flarum en la [etiqueta de extensiones](https://discuss.flarum.org/t/extensions). Otras personas pueden instalar su extensión usando el siguiente comando:
+
+```bash
+composer require vendor/package
+```
\ No newline at end of file
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md
new file mode 100644
index 000000000..5e2cb1d54
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md
@@ -0,0 +1,122 @@
+# Extending Extensions
+
+Flarum extensions aren't just for adding features to core: extensions can extend other extensions!
+
+:::tip
+
+To learn how to make your extension extensible, see the [relevant documentation](extensibility.md)
+
+:::
+
+## Dependencies
+
+If your extension relies on another extension, you'll want to ensure that:
+
+- The other extension is installed and enabled before yours can be.
+- The other extension can't be disabled while yours is enabled.
+- The other extension is booted before your extension.
+
+Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section.
+
+For example, if you were building a new theme for the Flarum Tags extension, your `composer.json` would look like this:
+
+```json
+{
+ // ...
+ "require": {
+ "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core.
+ "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension.
+ },
+ // ...
+}
+```
+
+## Optional Dependencies
+
+Sometimes, extension A might want to extend extension B only if extension B is enabled. In this case, we call B an "Optional Dependency" of A. For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled.
+
+The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. Por ejemplo:
+
+```js
+if ('some-extension-id' in flarum.extensions) {
+ // do something
+}
+```
+
+In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. Por ejemplo:
+
+```php
+extensions = $extensions;
+ }
+
+ public function someMethod()
+ {
+ if ($this->extensions->isEnabled('some-extension-id')) {
+ // do something.
+ }
+ }
+}
+```
+
+Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json.
+
+Por ejemplo:
+
+```json
+{
+ // ...
+ "extra": {
+ "flarum-extension": {
+ "optional-dependencies": [
+ "flarum/tags"
+ ]
+ }
+ },
+ // ...
+}
+```
+
+## Importing from Extensions
+
+In the backend, you can import the classes you need via regular PHP `use` statements:
+
+```php
+ {
+ // Your Extension Code Here
+})
+
+export {
+ // Put all the stuff you want to export here.
+}
+```
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md
new file mode 100644
index 000000000..ef202b2c7
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md
@@ -0,0 +1,129 @@
+# Filesystem
+
+Flarum core integrates with the filesystem to store and serve assets (like compiled JS/CSS or upload logos/favicons) and avatars.
+
+Extensions can use Flarum's provided utils for their own filesystem interaction and file storage needs. This system is based around [Laravel's filesystem tools](https://laravel.com/docs/8.x/filesystem), which are in turn based on the [Flysystem library](https://github.com/thephpleague/flysystem).
+
+## Disks
+
+Filesystem **disks** represent storage locations, and are backed by storage drivers, which we'll cover later. Flarum core has 2 disks: `flarum-assets` and `flarum-avatars`.
+
+### Using existing disks
+
+To access a disk, you'll need to retrieve it from the [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). To do so, you should inject the factory contract in your class, and access the disks you need.
+
+Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example:
+
+```php
+settings = $settings;
+ $this->uploadDir = $filesystemFactory->disk('flarum-assets');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function delete(ServerRequestInterface $request)
+ {
+ RequestUtil::getActor($request)->assertAdmin();
+
+ $path = $this->settings->get('logo_path');
+
+ $this->settings->set('logo_path', null);
+
+ if ($this->uploadDir->exists($path)) {
+ $this->uploadDir->delete($path);
+ }
+
+ return new EmptyResponse(204);
+ }
+}
+```
+
+The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource.
+
+### Declaring new disks
+
+Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`.
+
+This can be done via the `Filesystem` extender:
+
+```php
+use Flarum\Extend;
+
+return [
+ (new Extend\Filesystem)
+ ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) {
+ return [
+ 'root' => "$paths->public/assets/uploads",
+ 'url' => $url->to('forum')->path('assets/uploads')
+ ];
+ });
+```
+
+Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem.
+
+The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored.
+
+## Storage drivers
+
+Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver.
+
+You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender:
+
+```php
+use Flarum\Extend;
+
+return [
+ (new Extend\Filesystem)
+ ->driver('aws-with-cdn', AwsWithCdnDriver::class);
+```
+
+Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer.
+
+:::danger
+
+Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed.
+
+:::
+
+## GUI and Admin Configuration
+
+Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. For now, extensions are responsible for providing a GUI for their disks and drivers.
+
+As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings.
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md
new file mode 100644
index 000000000..5020b6774
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md
@@ -0,0 +1,42 @@
+# Formatting
+
+Flarum utiliza la potente biblioteca [s9e TextFormatter](https://github.com/s9e/TextFormatter) para dar formato a los mensajes desde el marcado simple hasta el HTML. Deberías familiarizarte con [cómo funciona TextFormatter](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) antes de intentar extenderlo.
+
+En Flarum, el contenido de las entradas se formatea con una configuración mínima de TextFormatter por defecto. Las extensiones **Markdown** y **BBCode** incluidas simplemente habilitan los respectivos plugins en esta configuración de TextFormatter.
+
+## Configuración
+
+Puedes configurar la instancia del `Configurador` de TextFormatter, así como ejecutar una lógica personalizada durante el análisis sintáctico y la renderización, utilizando el extensor `Formatter`:
+
+```php
+use Flarum\Extend;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use s9e\TextFormatter\Configurator;
+use s9e\TextFormatter\Parser;
+use s9e\TextFormatter\Renderer;
+
+return [
+ (new Extend\Formatter)
+ // Añadir la configuración del formateador de texto personalizado
+ ->configure(function (Configurator $config) {
+ $config->BBCodes->addFromRepository('B');
+ })
+ // Modificar el texto en bruto antes de analizarlo.
+ // Esta llamada de retorno debe devolver el texto modificado.
+ ->parse(function (Parser $parser, $context, $text) {
+ // lógica personalizada aquí
+ return $newText;
+ })
+ // Modificar el XML a renderizar antes de renderizar.
+ // Esta llamada de retorno debe devolver el nuevo XML.
+ // Por ejemplo, en la extensión de menciones, esto se utiliza para
+ // proporcionar el nombre de usuario y el nombre para mostrar del usuario que está siendo mencionado.
+ // Asegúrese de que el último argumento $request sea nulo (u omitido por completo).
+ ->render(function (Renderer $renderer, $context, $xml, Request $request = null) {
+ // lógica personalizada aquí
+ return $newXml;
+ })
+];
+```
+
+Con una buena comprensión de TextFormatter, esto le permitirá lograr cualquier cosa, desde simples adiciones de etiquetas BBCode hasta tareas de formato más complejas como la extensión **Mentions** de Flarum.
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/forms.md
new file mode 100644
index 000000000..f92cabe23
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/forms.md
@@ -0,0 +1,108 @@
+# Formularios y peticiones
+
+En este artículo, repasaremos algunas herramientas de frontend que tenemos a nuestra disposición para construir y gestionar formularios, así como la forma de enviar peticiones HTTP a través de Flarum.
+
+## Componentes de los formularios
+
+Como en cualquier sitio interactivo, es probable que quiera incluir formularios en algunas páginas y modales. Flarum proporciona algunos componentes para facilitar la construcción (¡y el estilo!) de estos formularios. Por favor, consulte la documentación de la API vinculada para cada uno de ellos para obtener más información sobre sus atributos aceptados.
+
+- El componente [`flarum/components/FieldSet`](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) envuelve a sus hijos en una etiqueta HTML fieldset, con una leyenda.
+- El componente [`flarum/components/Select`](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) es una entrada de selección estilizada.
+- Los componentes [`flarum/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) y [`flarum/components/Checkbox`](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) son componentes de entrada de casilla de verificación estilizados. Su attr `loading` puede establecerse en `true` para mostrar un indicador de carga.
+- El componente [`flarum/components/Button`](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) es un botón estilizado, y se utiliza frecuentemente en Flarum.
+
+Normalmente querrás asignar la lógica para reaccionar a los cambios de entrada a través de los attrs `on*` de Mithril, no de los listeners externos (como es común con jQuery o JS simple). Por ejemplo:
+
+```jsx
+import Component from 'flarum/Component';
+import FieldSet from 'flarum/components/FieldSet';
+import Button from 'flarum/components/Button';
+import Switch from 'flarum/components/Switch';
+
+
+class FormComponent extends Component {
+ oninit(vnode) {
+ this.textInput = "";
+ this.booleanInput = false;
+ }
+
+ view() {
+ return (
+
+ )
+ }
+
+ onsubmit() {
+ // Lógica de manejo de formularios aquí
+ }
+}
+```
+
+¡No olvides utilizar [traducciones](translate.md)!
+
+
+## Streams, bidi, y withAttr
+
+Flarum proporciona [Mithril's Stream](https://mithril.js.org/stream.html) como `flarum/util/Stream`. Esta es una estructura de datos reactiva muy poderosa, pero es más comúnmente usada en Flarum como una envoltura para datos de formularios. Su uso básico es:
+
+```js
+import Stream from 'flarum/utils/Stream';
+
+
+const value = Stream("hello!");
+value() === "hello!"; // verdadero
+value("world!");
+value() === "world!"; // verdadero
+```
+
+En los formularios de Flarum, los flujos se utilizan frecuentemente junto con el attr bidi. Bidi significa unión bidireccional, y es un patrón común en los frameworks de frontend. Flarum parchea Mithril con la librería [`m.attrs.bidi`](https://github.com/tobyzerner/m.attrs. Esto abstrae el procesamiento de la entrada en Mithril. Por ejemplo:
+
+```jsx
+import Stream from 'flarum/utils/Stream';
+
+const value = Stream();
+
+// Sin bidi
+ value(e.target.value)}>
+
+// Con bidi
+
+```
+
+También puedes utilizar la utilidad `flarum/utils/withAttr` para simplificar el procesamiento de formularios. `withAttr` llama a un callable, proporcionando como argumento algún attr del elemento DOM ligado al componente en cuestión:
+
+```jsx
+import Stream from 'flarum/utils/Stream';
+import withAttr from 'flarum/utils/withAttr';
+
+const value = Stream();
+
+// With a stream
+
+
+// With any callable
+ {
+ // Some custom logic here
+})}>
+```
+
+## Haciendo peticiones
+
+En nuestra documentación de [modelos y datos](data.md), aprendiste a trabajar con modelos, y a guardar la creación, los cambios y la eliminación de modelos en la base de datos a través de la utilidad Store, que no es más que una envoltura del sistema de peticiones de Flarum, que a su vez no es más que una envoltura del sistema de peticiones de [Mithril](https://mithril.js.org/request.html).
+
+El sistema de peticiones de Flarum está disponible globalmente a través de `app.request(options)`, y tiene las siguientes diferencias con respecto a `m.request(options)` de Mithril:
+
+- Adjuntará automáticamente las cabeceras `X-CSRF-Token`.
+- Convertirá las peticiones `PATCH` y `DELETE` en peticiones `POST`, y adjuntará una cabecera `X-HTTP-Method-Override`.
+- Si la petición da error, mostrará una alerta que, si está en modo de depuración, puede ser pulsada para mostrar un modal de error completo.
+- Puede proporcionar la opción `background: false`, que ejecutará la petición de forma sincronizada. Sin embargo, esto no debería hacerse casi nunca.
+
+Por lo demás, la API para utilizar `app.request` es la misma que la de `m.request`.
diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md
new file mode 100644
index 000000000..4add48b70
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md
@@ -0,0 +1,215 @@
+# Páginas del frontend y Resolvers
+
+Como se explica en la documentación de [Rutas y Contenido](routes.md#frontend-routes), podemos utilizar el sistema de rutas de Mithril para mostrar diferentes [componentes](frontend.md#components) para diferentes rutas. Mithril te permite usar cualquier componente que quieras, incluso un Modal o una Alerta, pero recomendamos ceñirse a las clases de componentes que heredan el componente `Page`.
+
+## El componente de la página
+
+Proporcionamos `flarum/components/Page` como una clase base para las páginas en los frontends `admin` y `forum`. Tiene algunos beneficios:
+
+- Actualiza automáticamente [`app.current` y `app.previous` PageState](#pagestate) cuando se cambia de una ruta a otra.
+- Cierra automáticamente el modal y el cajón cuando se cambia de una ruta a otra.
+- Aplica `this.bodyClass` (si está definido) al elemento HTML '#app' cuando la página se renderiza.
+- También es bueno, por coherencia, utilizar una clase base común para todas las páginas.
+- Si el atributo `scrollTopOnCreate` de la página se establece en `false` en `oninit`, la página no se desplazará a la parte superior cuando se cambie.
+- Si el atributo `useBrowserScrollRestoration` de la página se establece como `false` en `oninit`, la restauración automática del desplazamiento del navegador no se utilizará en esa página.
+
+Los componentes de página funcionan como cualquier otro componente heredado. Para un ejemplo (muy simple):
+
+```js
+import Page from 'flarum/components/Page';
+
+
+export default class CustomPage extends Page {
+ view() {
+ return
Hello!
+ } +} +``` + +### Usare i Route Resolvers + +Flarum utilizza un'impostazione per determinare quale pagina dovrebbe essere la homepage: questo dà flessibilità agli amministratori per personalizzare le loro community. Per aggiungere una pagina personalizzata alla homepage in Admin, è necessario estendere il metodo `BasicsPage.homePageItems` con il percorso della tua nuova pagina. + +I dati possono essere impostati e recuperati dallo stato della pagina utilizzando: + +```js +import IndexPage from 'flarum/components/DiscussionPage'; +import DiscussionPage from 'flarum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +Ad esempio, questo è il modo in cui la pagina di discussione fa la sua istanza di [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) disponibile a livello globale. + +### Resolvers personalizzati + +Spesso, la prima cosa che si modifica è il testo personalizzato che appare nel titolo della scheda del browser. Per esempio, una pagina di tag potrebbe voler mostrare "Tag - NOME FORUM", o una pagina di discussione potrebbe voler mostrare il titolo della discussione. + +Per fare ciò, dovrai aggiungere alla tua pagina la call `app.setTitle()` e `app.setTitleCount()` nel metodo `oncreate` del [lifecycle hook](frontend.md) (o quando i dati sono stati caricati, se richiesti tramite API). + +In realtà ci sono 3 modi per impostare il resolver di componenti / percorsi durante la registrazione di una route: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Si prega di notare che se la pagina è [impostata come homepage](#setting-page-as-homepage), `app.setTitle()` cancellerà il titolo per semplicità. Dovrebbe comunque essere impostato, per evitare che i titoli delle pagine precedenti vengano applicati. + +## PageState + +A volte, vogliamo ottenere informazioni sulla pagina in cui ci troviamo attualmente o sulla pagina da cui proveniamo. Per consentire ciò, Flarum crea (e memorizza) istanze di [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) come `app.current` e `app.previous`. Cioè: + +- La classe del componente utilizzata per la pagina +- Una raccolta di dati che ogni pagina imposta su se stessa. Il nome della rotta corrente è sempre incluso. + +I dati possono essere impostati e recuperati da Page State utilizzando: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +Ad esempio, ecco come la Pagina di Discussione rende [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) disponibile globalmente. + +Puoi anche controllare il tipo e i dati di una pagina usando `PostStreamState` ed il metodo `matches`. Ad esempio, se vogliamo sapere se siamo attualmente su una pagina di discussione: + +```jsx +// Vedi sopra per un esempio di pagina personalizzata +import CustomPage from './components/CustomPage'; +// Vedi sotto per un esempio di resolver personalizzato +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Utilizza un'istanza del resolver di percorsi +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Usa una classe di resolver di percorsi personalizzata +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Usa la classe di default (`flarum/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +## Route resolver (avanzato) + +Vedi la documentazione [Pannello di amministrazione](admin.md) per ulteriori informazioni sugli strumenti disponibili per le pagine di amministrazione (e su come sovrascrivere la pagina di amministrazione per la tua estensione). + +## Route Resolvers (Avanzato) + +[Casi d'uso avanzati](https://mithril.js.org/route.html#advanced-component-resolution) possono ottenere vantaggi dal [sistema di risoluzione dei percorsi di Mithril](https://mithril.js.org/route.html#routeresolver). Flarum in realtà avvolge già tutti i suoi componenti nel resolver `flarum/resolvers/DefaultResolver`. Ciò ha i seguenti vantaggi: + +- Passa un attributo `routeName` alla pagina corrente, che poi lo fornisce a`PageState` +- Assegna una [chiave](https://mithril.js.org/keys.html#single-child-keyed-fragments) al componente della pagina di primo livello. Quando il percorso cambia, se la chiave del componente di primo livello è cambiata, verrà riprodotto completamente (per impostazione predefinita, Mithril non esegue il rendering dei componenti quando si passa da una pagina all'altra se entrambi sono gestiti dallo stesso componente). + +### Usare i Route Resolvers + +Ci sono in realtà 3 modi per impostare il componente/route resolver durante la registrazione di un nuovo percorso: + +- la chiave `resolver` può essere usata per fornire un ** istanza ** di un risolutore di percorsi. Questa istanza dovrebbe definire quale componente deve essere utilizzato e codificare il nome del percorso da passare al suo interno. Questa istanza verrà utilizzata senza alcuna modifica da Flarum. +- Le chiavi `resolverClass` e `component` possono essere usate per fornire una ** classe ** che sarà utilizzata per istanziare un risolutore di percorsi, da usare al posto di quella predefinita di Flarum, così come il componente da usare. Il suo costrutto dovrebbe avere 2 argomenti: `(component, routeName)`. +- La chiave `component` può essere usata da sola per un componente. Ciò comporterà un comportamento predefinito. + +Per esempio: + +```js +//Guarda in alto per le pagine personalizzate +import CustomPage from './components/CustomPage'; +// Guarda in basso per i resolver personalizzati di esempio +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Usa un route resolver +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Utilizza un resolver personalizzato +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Usa la classe di default (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Resolver Personalizzati + +Consigliamo vivamente di estendere i risolutori di percorsi personalizzati `flarum/resolvers/DefaultResolver`. Per esempio, Flarum `flarum/resolvers/DiscussionPageResolver` assegna la stessa chiave a tutti i collegamenti alla stessa discussione (indipendentemente dal post corrente) e attiva lo scorrimento quando si utilizza `m.route.set` per passare da un post all'altro nella stessa pagina di discussione: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * Non viene esportato in quanto si tratta di una misura temporanea. + * Un sistema più robusto verrà implementato insieme al supporto UTF-8 nella beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * Un risolutore di percorsi personalizzato per DiscussionPage che genera la stessa chiave per tutti i post + * nella stessa discussione. Attiva uno scorrimento quando si passa da un post all'altro + * nella stessa discussione. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..9cc8aa444 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,502 @@ +# Sviluppo del Frontend + +Questa pagina descrive come apportare modifiche all'interfaccia utente di Flarum. Come aggiungere pulsanti, cornici e testo lampeggiante. 🤩 + +[Ricorda](/extend/start.md#architecture), Il frontend di Flarum � un ** applicazione JavaScript a pagina singola **. Non ci sono Twig, Blade o qualsiasi altro tipo di modelli PHP di cui parlare. I pochi modelli presenti nel back-end vengono utilizzati solo per il rendering di contenuto ottimizzato per i motori di ricerca. Tutte le modifiche all'interfaccia utente devono essere apportate tramite JavaScript. + +Flarum ha due applicazioni frontend separate: + +* `forum`, la parte pubblica del forum in cui gli utenti creano discussioni e post. +* `admin`, il lato privato del tuo forum dove, come amministratore del tuo forum, configuri la tua installazione di Flarum. + +Condividono lo stesso codice di base, quindi una volta che sai come estenderne uno, sai come estenderli entrambi. + +:::tip Typings! + +Insieme al nuovo supporto TypeScript, abbiamo un pacchetto [`tsconfig`](https://www.npmjs.com/package/flarum-tsconfig) disponibile, che si dovrebbe installare come dipendenza per ottenere accesso ai nostri typings durante lo sviluppo. Assicurati di seguire le istruzioni contenute nel README del pacchetto + + per configurare il supporto ai typings. + +::: + + + +## Struttura dei File + +Questa parte della guida spiegher� la configurazione dei file necessaria per le estensioni. Ancora una volta, consigliamo vivamente di utilizzare [FoF extension generator (non ufficiale)](https://github.com/FriendsOfFlarum/extension-generator) per impostare la struttura di base per te. Detto questo, dovresti comunque leggere questa guida per capire cosa accade sotto la superficie. + +Prima di poter scrivere qualsiasi JavaScript, dobbiamo impostare un **transpiler**. Questo ti permetter� di utilizzare [TypeScript](https://www.typescriptlang.org/) e la sua magia nel nucleo e nelle estensioni di Flarum. + +Per fare ci�, devi lavorare in un ambiente adatto. No, non il tipo di ambiente di casa/ufficio - puoi lavorare in bagno per quel che ci importa! Stiamo parlando degli strumenti installati sul tuo sistema. Avrai bisogno: + +* Node.js e npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +Questo pu� essere complicato perch� il sistema di ognuno � diverso. Dal sistema operativo che stai utilizzando, alle versioni del programma che hai installato, alle autorizzazioni di accesso dell'utente – Ci vengono i brividi solo a pensarci! Se incappi nei guai, ~~ti salutiamo~~ usa [Google](https://google.com) per vedere se qualcuno ha riscontrato il tuo stesso errore e ha trovato una soluzione. In caso contrario, chiedi aiuto nel [Forum di Flarum](https://flarumit.it) o su [Discord chat](https://flarum.org/discord/). + +� ora di impostare il nostro piccolo progetto di traspilazione JavaScript. Crea una nuova cartella nella tua estensione chiamata `js`, quindi inserisci un paio di nuovi file. Una tipica estensione avr� la seguente struttura di frontend: + + + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +└── webpack.config.json +``` + + + + +### package.json + + + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "0.1.0-beta.10", + "webpack": "^4.0.0", + "webpack-cli": "^3.0.7" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + + +Questo � un [pacchetto](https://docs.npmjs.com/files/package.json) standard di JS, usato da npm e Yarn (Gestori di pacchetto javascript). Puoi usarlo per aggiungere comandi, dipendenze js e metadati del pacchetto. In realt� non stiamo pubblicando un pacchetto npm: questo � semplicemente usato per raccogliere le dipendenze. + +Si prega di notare che non � necessario includere `flarum/core` o qualsiasi estensione flarum come dipendenze: verranno automaticamente pacchettizzate quando Flarum compila i frontend per tutte le estensioni. + + + +### webpack.config.js + + + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + + +[Webpack](https://webpack.js.org/concepts/) � il sistema che effettivamente compila e raggruppa tutto il javascript (e le sue dipendenze) per la nostra estensione. Per funzionare correttamente, le nostre estensioni dovrebbero utilizzare il [Webpack ufficiale di configurazione Flarum](https://github.com/flarum/flarum-webpack-config) (mostrato nell'esempio sopra). + + + +### admin.js e forum.js + + + +```json +{ + // Usa il tsconfig di Flarum come punto di partenza + "extends": "flarum-tsconfig", + // Questo corrisponderà a tutti . s, .tsx, .d.ts, .js, . file sx nella tua cartella `src` + // e dice anche al tuo server Typescript di leggere i typings globali del core per + // l'accesso a `dayjs` e `$` nel namespace globale. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + + +Questo è una configurazione standard per abilitare il supporto aTypescript con le opzioni di cui Flarum ha bisogno. + +Assicurati sempre di usare l'ultima versione del file: https://github.com/flarum/flarum-tsconfig#readme. + +Di seguito esamineremo gli strumenti disponibili per le estensioni. + +Per far funzionare i typings, dovrai eseguire `composer update` nella cartella delle tue estensioni per scaricare l'ultima copia del core di Flarum in una nuova cartella `vendor`. Ricordati di non eseguire il commit di questa cartella se stai usando un sistema come Git. + +Potrebbe essere necessario anche riavviare il server TypeScript dell'IDE. In Visual Studio Code, è possibile premere F1, quindi digitare "Riavvia TypeScript Server" e premere INVIO. Potrebbe richiedere qualche minuto per il suo completamento. + + + +### admin.js e forum.js + +Questi file contengono la radice del nostro JS di frontend effettivo. Potresti mettere qui l'intera estensione, ma non sarebbe ben organizzata. Per questo motivo, consigliamo di inserire il codice sorgente attuale in `src`, e avendo questi file solo esportare il contenuto di `src`. Per esempio: + + + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + + + + +### src + +Se si seguono le raccomandazioni per `admin.js` e `forum.js`, dovremmo avere 2 sottocartelle: una per il codice frontend di `admin`, ed una per il frontend fi `forum`. Se disponi di componenti, modelli, utilit� o altro codice condiviso tra entrambi i frontend, potresti voler creare un file `common` in una sottocartella. + +La struttura per `admin` e `forum` � identica, vi mostriamo quella di `forum` qui: + + + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + + +`components`, `models`, e `utils` sono directory che contengono file in cui � possibile definire [componenti personalizzati](#components), [modelli](data.md#frontend-models), e funzioni utili riutilizzabili. Tieni presente che questo � semplicemente un consiglio: non c'� nulla che ti costringa a utilizzare questa particolare struttura di file (o qualsiasi altra struttura di file). + +Il file pi� importante qui � `index.js`: tutto il resto � solo l'estrazione di classi e funzioni nei propri file. Esaminiamo un tipico `index.js`: + + + +```js +import {extend, override} from 'flarum/extend'; + +// We provide our extension code in the form of an "initializer". +// Questa è una callback che verrà eseguita dopo che il core è stato avviato. +app.initializers.add('our-extension', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + + +Vedremo gli strumenti disponibili per le estensioni qui sotto. + + + +### Transpilazione + +:::tip Librerie esterne + +Praticamente ogni estensione Flarum dovr� importare * qualcosa * da Flarum Core. Come la maggior parte delle estensioni, il codice sorgente JS di core � suddiviso in cartelle `admin`, `common`, e `forum`. Tuttavia, viene esportato tutto in `flarum`. Per elaborare: + +In alcuni casi, un'estensione potrebbe voler estendere il codice da un'altra estensione flarum. Questo � possibile solo per le estensioni che esportano esplicitamente il loro contenuto. + +* `flarum/tags` e `flarum/flags` sono attualmente le uniche estensioni in bundle che consentono di estendere il proprio JS. Puoi importare i loro contenuti da `flarum/{EXT_NAME}/PATH` (es. `flarum/tags/components/TagHero`). +* Il processo per estendere i plugin della community è diverso; è necessario consultare la documentazione per ogni singola estensione. + + + +### Transpilazione + +OK, � ora di accendere il transpiler. Esegui i seguenti comandi nella directory `js`: + + + +```bash +npm install +npm run dev +``` + + +Questo compilerà il tuo codice JavaScript pronto per il browser nel file `js/dist/forum.js`, e continuerà a compilarne le modifiche ai file di origine in tempo reale. Carino! + +Quando hai finito di sviluppare la tua estensione (o prima di una nuova versione), ti consigliamo di eseguire `npm run build` invece di `npm run dev`: questo crea l'estensione in modalità di produzione, che renderà il codice sorgente più snello e più veloce. + + + +## Registrazione Asset + + + +### JavaScript + +Affinché il JavaScript della tua estensione possa essere caricato nel frontend, dobbiamo dire a Flarum dove trovarlo. Possiamo farlo usando l'extender `Frontend` e metodo `js`. Aggiungilo alla tua estensione nel file `extend.php`: + + + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + + +Flarum renderà tutto ciò che esporti con `export` da `forum.js` disponibile nell'oggetto `flarum.extensions['acme-hello-world']`. Inoltre, puoi scegliere di esporre la tua API pubblica per consentire ad altre estensioni di interagire. + +:::tip Librerie Esterne + +È consentito solo un file JavaScript principale per estensione. Se è necessario includere una libreria JavaScript esterna, è possibile sia installarla con NPM e `import` in modo che siano compilati nel tuo file JavaScript, o vedi [Percorsi e Contenuti](/extend/routes.md) per imparare ad aggiungere tag aggiuntivi `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..3872f2975 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Cerca + +Flarum tratta la ricerca e il filtraggio come processi paralleli ma distinti. Quale processo viene utilizzato per gestire una richiesta a [`List` API endpoint](/extend/api.md#api-endpoints) dipende dai parametri della query: + +- Il filtro viene applicato quando il parametro della query `filter[q]` viene omesso. I filtri rappresentano **query strutturate**: per esempio, potresti voler recuperare solo le discussioni in una determinata categoria, o gli utenti che si sono registrati prima di una certa data. Filtrando i risultati dei calcoli basati interamente sui parametri `filter[KEY] = VALORE` query. +- La ricerca viene applicata quando il `filter[q]` query param è incluso. Le ricerche rappresentano **query non strutturate** : l'utente invia una stringa arbitraria e i record di dati che "corrispondono" sono restituiti. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Ricerca dei risultati dei calcoli basata esclusivamente sull'analisi del parametro `filter[q]`: tutti gli altri `filter[KEY] = VALUE` vengono ignorati durante la ricerca. È importante notare che le ricerche non sono completamente strutturate: il set di dati ricercato può essere vincolato dai gambits (che sono molto simili ai filtri, e li vedremo più avanti). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..7d8590174 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Provider di servizi + +Come notato in questa documentazione, Flarum utilizza [il contenitore dei servizi Laravel](https://laravel.com/docs/6.x/container) (o IoC container) per l'iniezione di dipendenze. [I provider di servizi](https://laravel.com/docs/6.x/providers) consentono la configurazione e la modifica del backend Flarum a basso livello. Il caso d'uso più comune per i provider di servizi è creare, modificare o sostituire i binding del contenitore. Detto questo, i provider di servizi consentono l'accesso completo per eseguire qualsiasi logica necessaria durante l'avvio dell'applicazione con accesso al contenitore. + +:::caution Solo per utenti avanzati!!! + +A differenza di altri estensori, il livello del provider di servizi NON è basato sul caso d'uso e NON è considerato API pubblica. È soggetto a modifiche in qualsiasi momento, senza preavviso. E dovrebbe essere usato solo se sai cosa stai facendo e gli altri extender non soddisfano il tuo caso d'uso. + +::: + +## Processi di Boot di Flarum + +Per comprendere i provider di servizi, devi prima capire l'ordine in cui Flarum si avvia. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. Il contenitore e l'applicazione vengono inizializzati e vengono registrati i collegamenti essenziali (configurazione, ambiente, logger) +2. Il metodo `register` di tutti i principali provider di servizi viene eseguito. +3. Il metodo `extend`di tutti gli extender utilizzati dalle estensioni sono avviati. +4. Il metodo `extend` di tutti gli extender utilizzati nel file Flarum `extend.php` è avviato. +5. Il metodo `boot` di tutti i provider di servizi principali è avviato. + +## Provider di servizi personalizzato + +Un provider di servizi personalizzato dovrebbe estendersi in `Flarum\Foundation\AbstractServiceProvider`, e può avere metodi `boot` e `register`. Per esempio: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +Il metodo `register` verrà eseguito durante il passaggio (3) qui sopra, e il metodo `boot` verrà eseguito durante la fase (5). In entrambi i metodi, il contenitore è disponibile tramite `$this->app`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +Per registrare effettivamente il tuo provider di servizi personalizzato, puoi utilizzare l'extender `ServiceProvider` in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..a8e15e917 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Impostazioni + +Ad un certo punto durante la creazione di un'estensione, potresti voler leggere alcune delle impostazioni del forum o memorizzare determinate impostazioni specifiche per la tua estensione. Per fortuna, Flarum lo rende molto semplice. + +## La repository Impostazioni + +La lettura o la modifica delle impostazioni può essere eseguita utilizzando un'implementazione di `SettingsRepositoryInterface`. Invece, puoi fare affidamento sul contenitore per istanziare la tua classe e inserire le dipendenze corrette. Poichè Flarum utilizza [il contenitore di servizi di Laravel](https://laravel.com/docs/6.x/container) (o IoC container)per l'inserimento di dipendenze, non è necessario preoccuparsi di dove ottenere tale repository o di come istanziarne una. + +```php +settings = $settings; + } +} +``` + +Grande! Perfetto, ora `SettingsRepositoryInterface` è disponibile tramite la classe `$this->settings`. + +### Leggere le impostazioni + +Per leggere le impostazioni, tutto ciò che dobbiamo fare è utilizzare la funzione della repository `get()`: + +`$this->settings->get('forum_title')` + +La funzione `get()` accetta i seguenti argomenti: + +1. Il nome dell'impostazione che stai tentando di leggere. +2. (Facoltativo) Un valore predefinito se non è stato memorizzato alcun valore per tale impostazione. Per impostazione predefinita, questo sarà `null`. + +### Memorizzazione delle impostazioni + +Memorizzare le impostazioni è altrettanto facile, usa la funzione `set()`: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +La funzione `set` accetta i seguenti argomenti: + +1. Il nome dell'impostazione che stai tentando di modificare. +2. Il valore che desideri memorizzare per questa impostazione. + +### Altre funzioni + +La funzione `all()` restituisce un array di tutte le impostazioni conosciute. + +La funzione `delete($name)` ti consente di rimuovere un'impostazione con nome. + +## Impostazioni nel frontend + +### Modifica delle impostazioni + +Per ulteriori informazioni sulla gestione delle impostazioni tramite la dashboard dell'amministratore, consultare la [documentazione pertinente](admin.md). +### Accesso alle impostazioni + +Tutte le impostazioni sono disponibili nel frontend `admin` tramite `app.data.settings`. Tuttavia, questo non viene mostrato nel frontend `forum`, poiché chiunque può accedervi e non vorrai perdere tutte le tue impostazioni! (Scherzi a parte, potrebbe essere una violazione dei dati molto problematica). + +Se invece vogliamo utilizzare le impostazioni nel frontend `forum`, dovremo serializzarli e inviarli insieme al payload iniziale dei dati del forum. + +Questo può essere fatto tramite l'extender `Settings`. Per esempio: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }), +] +``` + +Ora, l'impostazione `my.cool.setting.key` sarà disponibile nel frontend come `app.forum.attribute("myCoolSetting")`, e il nostro valore modificato sarà accessibile tramite `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..288dc9269 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Modello Slugging diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..ce22a2d9d --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Iniziare + +Vuoi costruire un'estensione Flarum? Sei nel posto giusto! Questo documento ti guider� attraverso alcuni concetti essenziali, dopodich� costruirai la tua prima estensione Flarum da zero. + +## Architettura + +Per capire come estendere Flarum, prima dobbiamo capire un po' come � costruito Flarum. + +Tieni presente che Flarum utilizza alcuni linguaggi e strumenti _moderni_. Se hai mai creato solo plugin per WordPress prima, potresti sentirti un po' fuori dal tuo ambiente! Va bene, questo � un ottimo momento per imparare cose nuove e interessanti ed estendere le tue abilit�. Tuttavia, ti consigliamo di acquisire familiarit� con le tecnologie descritte di seguito prima di procedere. + +Flarum � composto da tre strati: + +* Primo, c'� il ** backend **. Questo � scritto in formato [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), e fa uso di un'ampia gamma di array e componenti [Laravel](https://laravel.com/) e pacchetti tramite [Composer](https://getcomposer.org/). Ti consigliamo anche di familiarizzare con il concetto di [iniezione dipendenze](https://laravel.com/docs/6.x/container), che viene utilizzato in tutto il nostro backend. + +* Secondo, il backend espone una ** API pubblica ** che consente ai client frontend di interfacciarsi con i dati del tuo forum. Questo � costruito secondo il [specifiche JSON:API](https://jsonapi.org/). + +* Ed ultimo, c'� l'interfaccia web predefinita che chiamiamo ** frontend **. Questa � una [applicazione a pagina singola](https://en.wikipedia.org/wiki/Single-page_application) che utilizza le API. � costruito con un semplice framework simile a React chiamato [Mithril.js](https://mithril.js.org). + +Le estensioni dovranno spesso interagire con tutti e tre questi livelli per far accadere le cose. Ad esempio, se si desidera creare un'estensione che aggiunga campi personalizzati ai profili utente, � necessario aggiungere le strutture di database appropriate nel ** backend **, esporre tali dati nell '** API pubblica ** e quindi visualizzare e consentire agli utenti di modificarlo sul ** frontend **. + +Allora ... come estendiamo questi livelli? + +## Extender + +Per estendere Flarum, useremo un concetto chiamato ** extender **. Gli extender sono oggetti * dichiarativi * che descrivono in termini semplici gli obiettivi che stai cercando di raggiungere (come aggiungere un nuovo percorso al tuo forum o eseguire del codice quando � stata creata una nuova discussione). + +Ogni extender � diverso. Tuttavia, saranno sempre in qualche modo simili a questo: + +```php +// Register a JavaScript and a CSS file to be delivered with the forum frontend +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +Creare prima un'istanza dell'extender, quindi chiamare i metodi su di essa per un'ulteriore configurazione. Tutti questi metodi restituiscono l'extender stesso, in modo da poter ottenere l'intera configurazione semplicemente concatenando le chiamate ai metodi. + +Per mantenere le cose coerenti, usiamo questo concetto di estensori sia nel backend (nel mondo PHP) che nel frontend (mondo JavaScript). _Tutto_ quello che fai nella tua estensione dovrebbe essere fatto tramite extender, perch� sono una ** garanzia ** che ti stiamo dando che una futura versione minore di Flarum non interromper� la tua estensione. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Ciao Mondo + +Vuoi vedere un extender in azione? Il file `extend.php` nella root della tua installazione di Flarum � il modo pi� semplice per registrare gli extender per il tuo sito. Dovrebbe restituire un array di oggetti extender. Aprilo e aggiungi quanto segue: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Ora visita il tuo forum per un saluto piacevole (anche se estremamente invadente). 👋 + +Per semplici personalizzazioni specifiche del sito come l'aggiunta di un po 'di CSS / JavaScript personalizzato o l'integrazione con il sistema di autenticazione del tuo sito, il file il file `extend.php` � praticamente perfetto. Ma a un certo punto, la tua personalizzazione potrebbe diventare troppo grande. Or maybe you have wanted to build an extension to share with the community from the get-go. � ora di costruire un'estensione! + +## Pacchetto estensione + +[Composer](https://getcomposer.org) � un gestore delle dipendenze per PHP. Consente alle applicazioni di inserire facilmente librerie di codice esterne e rende facile mantenerle aggiornate in modo che la sicurezza e le correzioni di bug vengano propagate rapidamente. + +A quanto pare, ogni estensione Flarum � anche un pacchetto Composer. Ci� significa che l'installazione di Flarum di qualcuno pu� "richiedere" una certa estensione e Composer la inserir� e la manterr� aggiornata. Bello no? + +Durante lo sviluppo, puoi lavorare sulle tue estensioni localmente e configurare un [repository di Composer](https://getcomposer.org/doc/05-repositories.md#path) per installare la tua copia locale. Crea una nuova cartella `packages` nella radice della tua installazione di Flarum, quindi esegui questo comando per dire a Composer che pu� trovare i pacchetti qui: + +```bash +composer config repositories.0 path "packages/*" +``` + +Ora iniziamo a costruire la nostra prima estensione. Crea una nuova cartella all'interno di quella `packages` per la tua estensione, chiamata `hello-world`. Vi inseriremo due file, `extend.php` e `composer.json`. Questi file sono il cuore e l'anima dell'estensione. + +### extend.php + +Il file `extend.php` � proprio come quello nella radice del tuo sito. Restituir� un array di oggetti extender che dicono a Flarum cosa vuoi fare. Per ora, spostati sull'extender `Frontend` fatto prima. + +### composer.json + +Dobbiamo parlare un po' a Composer del nostro pacchetto, e possiamo farlo creando un file `composer.json`: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": ">=0.1.0-beta.15 <0.1.0-beta.16" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* ** nome ** � il nome del pacchetto Composer nel formato `creatore/pacchetto`. + * Dovresti scegliere un nome fornitore che sia univoco, ad esempio il tuo nome utente GitHub. Ai fini di questo tutorial, supporremo che tu stia utilizzando `acme`come nome creatore. + * Dovresti aggiungere il prefisso `package` con `flarum-` per indicare che si tratta di un pacchetto specificamente destinato all'uso con Flarum. + +* **description ** � una breve descrizione composta da una frase che spiega ci� che fa l'estensione. + +* **type** DEVE essere impostato su `flarum-extension`. Ci� garantisce che quando qualcuno "richiede" la tua estensione, verr� identificato come tale. + +* **require** contiene un elenco delle dipendenze della tua estensione. + * Dovrai specificare la versione di Flarum con cui la tua estensione � compatibile qui. + * Questo � anche il posto dove elencare altre librerie Composer di cui il tuo codice ha bisogno per funzionare. + +* **autoload** dice a Composer dove trovare le classi della tua estensione. Il nome qui dovrebbe riflettere il fornitore delle estensioni e il nome del pacchetto in CamelCase. + +* **extra.flarum-extension** contiene alcune informazioni specifiche di Flarum, come il nome visualizzato dell'estensione e come dovrebbe apparire la sua icona. + * **title** � il nome visualizzato della tua estensione. + * **icon** � un oggetto che definisce l'icona della tua estensione. La propriet� ** name ** � un icona [Font Awesome](https://fontawesome.com/icons). Tutte le altre propriet� vengono utilizzate dall'attributo `style` per l'icona della tua estensione. + +Guarda la documentazione [schema di composer.json](https://getcomposer.org/doc/04-schema.md) documentation per informazioni su altre propriet� da aggiungere a `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Usa [FoF extension generator](https://github.com/FriendsOfFlarum/extension-generator) per creare automaticamente lo scheletro della tua estensione +```bash +$ flarum-cli init +``` + +::: + +### Installare la tua estensione + +L'ultima cosa che dobbiamo fare per essere operativi � installare la tua estensione. Vai alla directory root della tua installazione Flarum ed esegui il seguente comando + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Una volta fatto, vai avanti e avvia la pagina di amministrazione del tuo forum. + +*crank, ching, crunk* + +Oopl�! Ciao a te estensione Hello World! + +Stiamo facendo buoni progressi. Abbiamo imparato come impostare la nostra estensione e utilizzare gli estensori, il che apre molte porte. Continua a leggere per scoprire come estendere il frontend di Flarum. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..7b45a1f70 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Test + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + +something
Hello World!
; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +Per esempio: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. Per esempio: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return{this.counter}
; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +{this.attrs.counter}
; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +Counter: {app.counter.getCount()}
+Hello World!{this.showContent ? ' Extra Content!' : ''}
+Hello World!
Hello World
" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. The name of the invalid field is returned as the `pointer` value. There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..8c0aa5053 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Aspetto e Temi + +Anche se abbiamo lavorato duramente per rendere Flarum il più bello possibile, ogni comunità probabilmente vorrà apportare alcune modifiche grafiche o di stile per adattarlo alle proprie esigenze. + +## Pannello di amministrazione + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Da qui infatti si può: + +- Scegliere i colori principali del forum +- Attivare o meno la dark mode e scegliere il colore dell'header +- Caricare il tuo logo e favicon (l'icona visualizzata ai browser) +- Aggiungere html per personalizare header e footer +- Aggiungere [LESS/CSS](#css-theming) per cambiare la visualizzazione degli elementi + +## Il CSS nei temi + +CSS è un linguaggio per fogli di stile che indica ai browser come visualizzare gli elementi di una pagina web. Ci consente di modificare qualsiasi cosa, dai colori ai caratteri, alla dimensione degli elementi e al posizionamento delle animazioni. L'aggiunta di CSS personalizzati può essere un ottimo modo per modificare l'aspetto di Flarum in modo che corrisponda al tema del tuo sito. + +Un tutorial CSS va oltre lo scopo di questa documentazione, ma ci sono molte ottime risorse online per apprendere le basi dei fogli di stile. + +:::tip + +Flarum utilizza LESS, il che rende più facile scrivere CSS consentendo variabili, condizionali e funzioni. + +::: + +## Estensioni + +La flessibilità di Flarum nel [sistema di estensioni](extensions.md) ti consente di aggiungere, rimuovere o modificare praticamente ogni parte di Flarum. Se si desidera apportare modifiche sostanziali ai temi oltre a cambiare colori / dimensioni / stili, un'estensione personalizzata è sicuramente la strada da percorrere. Per sapere come creare un'estensione, dai un'occhiata alla [documentazione sulle estensioni](extend/README.md)! diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..0a287f292 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Risoluzione dei problemi + +Se Flarum non si installa o non funziona come previsto, la prima cosa da fare è controllare di nuovo se il proprio ambiente soddisfa [i requisiti necessari](install.md#server-requirements). Se ti manca qualcosa che è necessaria per l'esecuzione di Flarum, dovrai prima rimediare. + +Successivamente, dovresti impiegare alcuni minuti per cercare nel [Forum di supporto](https://discuss.flarum.org/t/support) e nell' [issue tracker](https://github.com/flarum/core/issues). È possibile che qualcuno abbia già segnalato il problema e una soluzione sia disponibile o in arrivo. Se hai cercato a fondo e non riesci a trovare alcuna informazione sul problema, è ora di iniziare la risoluzione dei problemi. + +## Step 0: Activate debug mode + +:::danger Salta in produzione + +Questi strumenti di debug sono molto utili, ma possono esporre informazioni che non dovrebbero essere pubbliche. These are fine if you're on a staging or development environment, but if you don't know what you're doing, skip this step when on a production environment. + +::: + +Prima di procedere, dovresti abilitare gli strumenti di debug di Flarum. Apri semplicemente il file **config.php** con un editor di testo, modifica il valore `debug` su `true`, e salva il file. uesto farà sì che Flarum visualizzi messaggi di errore dettagliati, dandoti un'idea di cosa non va. + +Se hai visto pagine vuote e la modifica sopra non aiuta, prova a impostare `display_errors` su `On` nel file di configurazione **php.ini**. + +## Step 1: Correzioni comuni + +A lot of issues can be fixed with the following: + +* Pulisci la cache del browser +* Pulisci la cache del backend con il comando [`php flarum cache:clear`](console.md). +* Assicurati che il tuo database sia aggiornato con il comando [`php flarum migrate`](console.md). +* Assicurati che [la configurazione email](mail.md) nel tuo pannello di amministrazione sia corretta: una configurazione e-mail non valida causerà errori durante la registrazione, la reimpostazione di una password, la modifica delle e-mail e l'invio di notifiche. +* Controlla che il tuo file `config.php` sia corretto. Ad esempio, assicurati di utilizzare un `url` corretto. +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +Dovrai anche dare un'occhiata all'output di [`php flarum info`](console.md) per assicurarti che nulla di importante sia fuori posto. + +## Step 2: Riproduci il problema + +Prova a far sì che il problema si ripresenti. Presta molta attenzione a ciò che stai facendo quando si verifica. Succede ogni volta o solo di tanto in tanto? Prova a cambiare un'impostazione che ritieni possa influire sul problema o l'ordine in cui stai facendo le cose. Succede in alcune condizioni, ma non in altre? + +Se hai recentemente aggiunto o aggiornato un'estensione, dovresti disabilitarla temporaneamente per vedere se questo risolve il problema. Assicurati che tutte le tue estensioni siano destinate ad essere utilizzate con la versione di Flarum che stai utilizzando. Le estensioni obsolete possono causare una serie di problemi. + +Da qualche parte lungo la strada potresti avere un'idea di cosa sta causando il tuo problema e trovare un modo per risolverlo. Ma anche se ciò non accade, probabilmente ti imbatterai in alcuni preziosi indizi che ci aiuteranno a capire cosa sta succedendo, una volta che avrai presentato la tua segnalazione di bug. + +## Step 3: Raccogli informazioni + +Se sembra che avrai bisogno di aiuto per risolvere il problema, è ora di fare sul serio nella raccolta dei dati. Cerca messaggi di errore o altre informazioni sul problema nei seguenti punti: + +* Visualizzato nella pagina attuale +* Visualizzato nella console del browser (Chrome: More tools -> Developer Tools -> Console) +* Registrato nel registro degli errori del server (es. `/var/log/nginx/error.log`) +* Registrato nel log PHP-FPM's (es. `/var/log/php7.x-fpm.log`) +* Registrato da Flarum (`storage/logs/flarum.log`) + +Copia i messaggi in un file di testo e prendi nota di quando si è verificato l'errore, cosa stavi facendo in quel momento e così via. Assicurati di includere tutti gli approfondimenti che potresti aver raccolto sulle condizioni in cui il problema si verifica e non si verifica. Aggiungi quante più informazioni possibili sul tuo ambiente server: versione del sistema operativo, versione del server web, versione e gestore di PHP, ecc. + +## Step 4: Prepara un report + +Dopo aver raccolto tutte le informazioni possibili sul problema, sei pronto per presentare una segnalazione di bug. Si prega di seguire le istruzioni [per segnalare bug](bugs.md). + +Se scopri qualcosa di nuovo sul problema dopo aver inviato la segnalazione, aggiungi tali informazioni in fondo al tuo post originale. È una buona idea presentare un rapporto anche se hai risolto il problema da solo, poiché anche altri utenti potrebbero trarre vantaggio dalla tua soluzione. Se hai trovato una soluzione temporanea al problema, assicurati mettercene a conoscenza. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..fde68ef57 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Aggiornare la versione di Flarum + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +To update Flarum, you'll need to use [Composer](https://getcomposer.org). If you're not familiar with it (although you should be, because you need it to install Flarum), read [our guide](composer.md) for information on what it is and how to set it up. + +If updating across major versions (e.g. <=0.1.0 to 1.x.x, 1.x.x to 2.x.x, ...), make sure to read the appropriate "major version update guide" before running the general upgrade steps. + +## General Steps + +**Step 1:** Make sure all your extensions have versions compatible with the Flarum version you're trying to install. This is only needed across major versions (e.g. you probably don't need to check this if upgrading from v1.0.0 to v1.1.0, assuming your extensions follow recommended versioning). You can check this by looking at the extension's [Discuss thread](https://discuss.flarum.org/t/extensions), searching for it on [Packagist](http://packagist.org/), or checking databases like [Extiverse](https://extiverse.com). You'll need to remove (not just disable) any incompatible extensions before updating. Please be patient with extension developers! + +**Step 2:** Take a look at your `composer.json` file. Unless you have a reason to require specific versions of extensions or libraries, you should set the version string of everything except `flarum/core` to `*` (including `flarum/tags`, `flarum/mentions`, and other bundled extensions). Make sure `flarum/core` is NOT set to `*`. If you're targeting a specific version of Flarum, set `flarum/core` to that (e.g. `"flarum/core": "v0.1.0-beta.16`). If you just want the most recent version, use `"flarum/core": "^1.0"`. + +**Step 3:** If your local install uses [local extenders](extenders.md), make sure they are up to date with changes in Flarum. + +**Step 4:** We recommend disabling third-party extensions in the admin dashboard before updating. This isn't strictly required, but will make debugging easier if you run into issues. + +**Step 5:** Make sure your PHP version is supported by the version of Flarum you are trying to upgrade to, and that you are using Composer 2 (`composer --version)`. + +**Step 6:** Finally, to update, run: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Step 7:** If applicable, restart your PHP process and opcache. + +## Major Version Update Guides + +### Updating from Beta (<=0.1.0) to Stable v1 (^1.0.0) + +1. Do steps 1-5 above. +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## Troubleshooting Issues + +Mentre Flarum è in fase beta, le istruzioni e le modalità di aggiornamento verranno scritte direttamente nel forum inglese: [annunci sui rilasci](https://discuss.flarum.org/t/blog?sort=newest). + +### Errors While Updating + +Here we'll go through several common types of issues while trying to update Flarum. + +--- + +If the output is short and contains: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errori Dopo L'Aggiornamento + +Se non riesci ad accedere al tuo forum dopo l'aggiornamento, segui le nostre [istruzioni per la risoluzione dei problemi](troubleshoot.md). diff --git a/i18n/tr/docusaurus-plugin-content-docs/current.json b/i18n/tr/docusaurus-plugin-content-docs/current.json index ac470d0fc..72eb041ab 100644 --- a/i18n/tr/docusaurus-plugin-content-docs/current.json +++ b/i18n/tr/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Sonraki", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Internal Docs", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..7e17cf8e2 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# Flarum Hakkında + +Flarum, web siteniz için oldukça basit bir tartışma platformudur. Başarılı bir topluluk yürütmek için ihtiyacınız olan tüm özelliklerle birlikte kullanımı hızlı ve kolaydır. Aynı zamanda son derece genişletilebilir olup, en üst düzeyde özelleştirilebilirliğe olanak tanır. + + + +## Hedefler + +Flarum, [esoTalk](https://github.com/esotalk/esoTalk) ve [FluxBB](https://fluxbb.org)'nin birleşik halefidir. Şu şekilde tasarlanmıştır: + +* **Hızlı ve basit.** Dağınıklık yok, şişkinlik yok, karmaşık bağımlılıklar yok. Flarum PHP ile oluşturulmuştur, bu nedenle dağıtımı hızlı ve kolaydır. Arayüz, küçük bir ayak izine sahip, performanslı bir JavaScript çerçevesi olan [Mithril](https://mithril.js.org) tarafından desteklenmektedir. + +* **Güzel ve duyarlı.** Bu, insanlar için forum yazılımıdır. Flarum, kutudan çıkar çıkmaz tüm platformlarda tutarlı ve sezgisel olacak şekilde dikkatle tasarlanmıştır. + +* **Güçlü ve genişletilebilir.** Flarum'u topluluğunuza uyacak şekilde özelleştirin, genişletin ve entegre edin. Flarum’un mimarisi, [Güçlü Uzantı API'si](/extend/) ile inanılmaz derecede esnektir. + +* **Ücretsiz ve açıktır.** Flarum, [MIT lisansı](https://github.com/flarum/flarum/blob/master/LICENSE) altında yayınlanmıştır. + +[Flarum'a yönelik felsefemiz ve değerlerimiz](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values) hakkında daha fazla bilgi edinebilirsiniz. + +## Flarum Projesine Yardım Edin + +Flarum, gönüllüler tarafından bakımı yapılan ve yönetilen [ücretsiz, açık kaynaklı](https://github.com/flarum/core) bir yazılımdır. Flarum'u geliştirmemize ve genişletmemize yardımcı olması için topluluk katkılarına güveniyoruz. + +🧑💻 Eğer bir geliştiriciyseniz, Flarum'un temeline veya paketlenmiş uzantılarına katkıda bulunmayı düşünebilirsiniz. Bu, Flarum'a yardımcı olmanın en etkili yolu ve çalışmalarınızın büyük bir etkisi olabilir: milyonlarca son kullanıcıya sahip binlerce Flarum sitesi mevcuttur. + +🧩Eksik olduğunu düşündüğünüz bir özellik veya aklınıza gelen bir tema fikri varsa, [özel bir uzantı yazmak](extend/README.md) Flarum'u siz ve diğerleri için çok daha iyi hale getirecektir. + +✒️ Teknik yazım konusunda deneyiminiz varsa, [belgelerimize](https://github.com/flarum/docs/issues) yapacağınız katkılar gelecekteki kullanıcıların, yöneticilerin ve geliştiricilerin Flarum'dan en iyi şekilde yararlanmasına yardımcı olabilir. + +🌐 Birden fazla dil konuşuyorsanız Flarum'un dünya çapındaki sayısız kullanıcı tarafından erişilebilir olmasına yardımcı olmak için [çevirilere katkıda bulunabilirsiniz](extend/language-packs.md). + +💸 Flarum Vakfı, Flarum'dan para kazanmıyor ancak ödenmesi gereken faturaları var. [GitHub Sponsorları](https://github.com/sponsors/flarum) veya [OpenCollective](https://opencollective.com/flarum) aracılığıyla yapılan bağışlar her zaman minnetle alınır. Geçmişte, bazı temel geliştiricilerimizi finansal olarak da destekleyebildik, böylece onların Flarum'da yarı zamanlı çalışabilmesini sağladık. Maddi desteğiniz olmadan bu mümkün olmazdı. + +🧑🤝🧑 Flarum geliştirme hakkında konuşmak, örneğinizle ilgili yardım almak veya sadece harika insanlarla tanışmak için [topluluğumuza](https://discuss.flarum.org) katılın! Flarum konusunda deneyiminiz varsa yeni başlayanlara da yardımcı olabilirsiniz! + +🐛 Canınızı sıkan bir hata ya da aklınızda bir özellik fikri varsa siz bize söylemediğiniz sürece bunu bilemeyiz! Hataları, önerileri ve gelecekteki geliştirme planlarını [GitHub sorunları](https://github.com/flarum/core/issues) aracılığıyla takip ediyoruz. Zaten açık bir sorun varsa, beğeniler ve (yapıcı) ek bilgiler eklemek çok yararlı olabilir! + +📣 Ve eğer Flarum'u seviyorsanız, lütfen bunun hakkında blog yazmayı/tweetlemeyi/konuşmayı düşünün! Flarum'dan haberdar olan daha fazla insan, daha fazla insanın Flarum'la etkileşime geçmesine ve dolayısıyla daha fazla aktiviteye, daha iyi uzantılara ve daha hızlı gelişime yol açar. + +Olağanüstü topluluğumuz olmadan Flarum mümkün olmazdı. Katkıda bulunmak istiyorsanız daha fazla bilgi için [geliştirici katkısı](contributing.md) ve [diğer katkı](contributing-docs-translations.md) belgelerimize bakın. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..3b3ed3318 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# Yönetici Gösterge Tablosu + +Flarum Yönetici Panosu, forumunuzu yönetmek için kullanıcı dostu bir arayüzdür. Yalnızca "Yönetici" grubundaki kullanıcılar tarafından kullanılabilir. Yönetici panosuna erişmek için ekranın sağ üst köşesindeki **Adınıza** tıklayın ve **Yönetim**'i seçin. + +Yönetici Kontrol Panelinde aşağıdaki bölümler bulunur: +- **Kontrol Paneli** - İstatistikleri ve diğer ilgili bilgileri içeren ana Yönetici Kontrol Panelini gösterir. +- **Temel Bilgiler** - Ad, Açıklama ve Hoş Geldiniz Banner'ı gibi temel forum ayrıntılarını ayarlama seçeneklerini gösterir. +- **E-posta** - E-Posta ayarlarınızı yapılandırmanıza olanak tanır. Daha fazla bilgi için [buraya](https://docs.flarum.org/mail) bakın. +- **İzinler** - Her kullanıcı grubunun izinlerini gösterir ve genel ve belirli kapsamları yapılandırmanıza olanak tanır. +- **Görünüm** - Forumun renklerini, markasını özelleştirmenize ve özelleştirme için ek CSS eklemenize olanak tanır. +- **Kullanıcılar** - Forumdaki tüm kullanıcıların sayfalandırılmış bir listesini sağlar ve size kullanıcıyı düzenleme veya idari işlemler gerçekleştirme olanağı verir. + +Yönetici Kontrol Paneli, yukarıda bahsedilen bölümlerin dışında, _Özellikler_ bölümü altında Uzantılarınızı (Etiketler gibi flarum çekirdek uzantıları dahil) yönetmenize de olanak tanır. Forum temasını değiştiren veya birden fazla dil kullanmanıza olanak tanıyan uzantılar, sırasıyla _Temalar_ ve _Diller_ bölümünde kategorize edilmiştir. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..85e8ea193 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Reporting Bugs + +:::danger Security Vulnerabilities + +If you discover a security vulnerability within Flarum, please follow our [security policy](https://github.com/flarum/core/security/policy) so we can address it promptly. + +::: + +Thank you for helping us test Flarum. We're happy to have you on the team! We need people who can *troubleshoot issues patiently* and *communicate them clearly*. As you probably know, good bug reporting takes some time and effort. If you're fine with that, then let's get started! + +## Duplicates + +Found a bug already? Wonderful! We'd love to hear about it — but first you should check around to make sure you're not wasting your time on a known issue: + +- Search our [Support forum](https://discuss.flarum.org/t/support) to see if it's already been reported. +- We could be working on a fix, so search our [issue tracker](https://github.com/flarum/core/issues) too. + +If you've searched *thoroughly* and come up empty-handed, we'll welcome your report. If it's just a simple issue (a misspelled word or graphics glitch, for example) skip to the next paragraph. But if you're seeing errors, or something is clearly broken, we'll need you to gather some information first. Please head over to our [Troubleshooting](troubleshoot.md) guide and follow the instructions there. Collect as much info as you can! + +## Reporting + +We track issues on GitHub. Make sure you open your issue in the [correct repository](https://github.com/flarum), and fill out all of the information in the Bug Report template. + +If you can, check if the issue is reproducible with the latest version of Flarum. If you are using a pre-release or development version, please indicate the specific version you are using. + +Remember: the goal of a bug report is to make it easy for us to replicate the bug and fix it. You might want to read [this article](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for some useful tips on how to write an effective bug report. It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear reproduction steps will not be triaged. If an issue labeled "needs verification" receives no further input from the issue author for more than 5 days, it will be closed. + +Once you've posted your report, we'd ask that you please *follow the discussion* and wait patiently. We may need to ask for further details or clarification; but we've always got plenty to do, and it could be a while before we can give your report the time it deserves. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..6041c1b6e --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Davranış Kuralları + +### _Flarum Topluluğuna Hoş Geldiniz!_ + +... Ve bize katıldığınız için teşekkürler! Flarum için heyecanlıyız ve aynı şekilde hisseden insanlarla tanışmaktan her zaman mutluyuz. *Herkesin* Flarum ve Flarum topluluğundan en iyi şekilde yararlanmasını istiyoruz, bu nedenle bu yönergeleri okuyup uygulamanızı rica ediyoruz. Bunlar, forumumuzu, Discord sohbetini, GitHub'da iletişim kurmayı veya Flarum topluluğu olmadan başka herhangi bir iletişim biçimini kullanıyor olsanız da geçerlidir. + +### Her Şeyden Önce Sakin Olun! + +Hepimiz Flarum hakkında konuşmak ve onu daha iyi bir uygulama haline getirmek için birlikte çalışmak için buradayız. Fikirleri eleştirmek (elbette gerekçeli argümanlar aracılığıyla) bunun önemli bir parçasıdır. Ama kendimizi kaptırıp kişisel saldırılara geçmeyelim, çünkü olumsuzluk sadece araya girer. Aşağıdakilerden kaçınmanızı rica ediyoruz: + +- Saldırgan veya taciz edici dil ve ayrıca her türlü nefret söylemi +- Başkalarını taciz etmeyi, taklit etmeyi veya karalamayı amaçlayan gönderiler +- Gönderilen içeriğin gereksiz yere silinmesi +- Başkalarının özel bilgilerini kötüye kullanma veya ifşa etme girişimleri +- Müstehcen içerik +- Spam, kimlik avı gönderileri ve bu siteyi tahrif etmeye yönelik her türlü eylem +- Yazılım korsanlığı ve benzeri konuların tartışılması + +*Yukarıdakilerin tümü moderatör eylemi gerekçesidir.* Başka bir üyeyle bir sorununuz varsa, lütfen onlarla kendi başınıza yüzleşmemenizi rica ederiz. Forumdaysa, lütfen söz konusu gönderide *Report* komutunu kullanın, ardından durumla ilgilenmesi için bunu yetkiliye bırakın. Aksi takdirde ihlali [iletişim sayfamızdaki](https://flarum.org/foundation/contact) Yasal seçeneğini kullanarak bildirin. + +Moderatörlerimiz, saldırgan veya iletişim akışını aksatan herhangi bir içeriği düzenleyebilir veya silebilir. Ciddi veya tekrarlanan suçlar, ihlalde bulunan kullanıcının hesabının askıya alınmasına neden olabilir. Yani, bilirsin, *sakin ol*. 😎 + +### Duyulmasını Sağlayın + +Yeni bir tartışma başlatmak ister misiniz? Öncelikle [SSS](faq.md) bölümünü okuduğunuzdan ve proje hakkında tam olarak bilgi sahibi olduğunuzdan emin olmak için bağlantıları takip ettiğinizden emin olun. Daha sonra foruma göz atmak için biraz zaman ayırın, [etiket sistemi](https://discuss.flarum.org/tags) hakkında bilgi edinin ve konunuzla ilgili anahtar kelimeler için birkaç arama yapın: *birisi çoktan bunun hakkında bir tartışma başlamış olabilir!* + +Bir tartışma başlatmaya hazır olduğunuzdan emin olduğunuzda lütfen aşağıdaki noktaları aklınızda bulundurun: + +- Ona iyi bir başlık ver! Başlığınız ne hakkında konuşmak istediğinizi netleştirirse en iyi sonuçları alırsınız. +- Doğru etiketleri seçin. Bu, gönderinizin hemen okunma ve yanıtlanma olasılığını artıracaktır. +- Aynı tartışma ilgili tekrar tekrar *yayınlamayın*, çünkü bunu yapmak ters etki yaratır. +- Çok dilli kullanıma ayrılmış bir etiket kullanmıyorsanız *yalnızca İngilizce yayınlayın.* Gönderilerinizi anlamazsak size yardımcı olamayız. +- Unutmayın, yazılarınızı imzalamanıza gerek yok. Kim olduğunuzu bize bildirmek için profilinize bakıyoruz. + +Lütfen işleri organize etmemize yardımcı olmak için çaba gösterin. Toparlanmak için harcanan zaman, sizi tanımak, sorunlarınızı tartışmak ve Flarum hakkında konuşmak için harcayamayacağımız zamandır. Ve sonuçta, hepimiz yapmak için buradayız! + +### Yanıtınızı Sayın + +Başkalarının fikirlerinizi okuyup dikkate alması umuduyla bir tartışmaya katılmak için zaman ayırıyorsunuz. Öyleyse neden yanıtınızı okumaya değer kılmak için çaba harcamıyorsunuz? + +- Bir başlığı yanıtlamayın. İlk gönderiyi *okumak* için biraz zaman ayırın ve en azından tartışmanın geri kalanına *göz atın*. +- Cevabınızın tartışmaya katkıda bulunup bulunmadığını kendinize sorun. Olmazsa, yayınlamadan önce biraz daha düşünün. +- Birisiyle aynı fikirde olmak için tek kelimelik yazılar yapmaktan kaçının; bunun için "Like" düğmesini kullanabilirsiniz. +- Yeterli olduğunda arka arkaya birden fazla gönderi yapmaktan kaçının. Bu bir forum, sohbet odası değil. +- Cevabınız tartışmanın yönünü değiştirecekse, bunun yerine yeni bir tartışma başlatmayı düşünün. +- Test olarak biraz saçma sapan yayınlamak istiyorsanız, lütfen bunu [Test Posting](https://discuss.flarum.org/t/sandbox) etiketinde yapın. +- Yanıtlarınızın, kapsayıcı bir topluluğa izin vermek için yapıcı geri bildirim ve destek sağladığından emin olun. + +Hiç kimse ara sıra yapılan şakadan veya akıllıca sözlerden şikayet etmeyecek. Ruh halini hafif tutmayı seviyoruz! Ama aynı zamanda her şeyi üretken tutmak için, bir tartışmayı tamamen raydan çıkarmaktan kaçınmanızı istiyoruz. + +> Bu kuralları bir araya getirmedeki yardımlarından dolayı Dominion'a teşekkürler. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..f8c126903 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum uses a program called [Composer](https://getcomposer.org) to manage its dependencies and extensions. You'll need to use composer if you want to: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +This guide is provided as a brief explanation of Composer. We highly recommend consulting the [official documentation](https://getcomposer.org/doc/00-intro.md) for more information. + +:::tip Paylaşımlı Hosting + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## What is Composer? + +> Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Each Flarum installation consists primarily of Flarum core and a set of [extensions](extensions.md). Each of these has its own dependencies and releases. + +Back in the day, forum frameworks would manage extensions by having users upload zip files with the extension code. That seems simple enough, but issues quickly become evident: + +- Uploading random zip files from the internet tends to be a bad idea. Requiring that extensions be downloaded from a central source like [Packagist](https://packagist.org/) makes it somewhat more tedious to spam malicious code, and ensures that source code is available on GitHub for free/public extensions. +- Let's say Extension A requires v4 of some library, and Extension B requires v5 of that same library. With a zip-based solution, either one of the two dependencies could override the other, causing all sorts of inconsistent problems. Or both would attempt to run at once, which would cause PHP to crash (you can't declare the same class twice). +- Zip files can cause a lot of headache if trying to automate deployments, run automated tests, or scale to multiple server nodes. +- There is no good way to ensure conflicting extension versions can't be installed, or that system PHP version and extension requirements are met. +- Sure, we can upgrade extensions by replacing the zip file. But what about upgrading Flarum core? And how can we ensure that extensions can declare which versions of core they're compatible with? + +Composer takes care of all these issues, and more! + +## Flarum and Composer + +When you go to [install Flarum](install.md#installing), you're actually doing 2 things: + +1. Downloading a boilerplate "skeleton" for Flarum. This includes an `index.php` file that handles web requests, a `flarum` file that provides a CLI, and a bunch of web server config and folder setup. This is taken from the [`flarum/flarum` github repository](https://github.com/flarum/flarum), and doesn't actually contain any of the code necessary for Flarum to run. +2. Installing `composer` packages necessary for Flarum, namely Flarum core, and several bundled extensions. These are called by the `index.php` and `flarum` files from step 1, and are the implementation of Flarum. These are specified in a `composer.json` file included in the skeleton. + +When you want to update Flarum or add/update/remove extensions, you'll do so by running `composer` commands. Each command is different, but all commands follow the same general process: + +1. Update the `composer.json` file to add/remove/update the package. +2. Do a bunch of math to get the latest compatible versions of everything if possible, or figure out why the requested arrangement is impossible. +3. If everything works, download new versions of everything that needs to be updated. If not, revert the `composer.json` changes + +When running `composer.json` commands, make sure to pay attention to the output. If there's an error, it'll probably tell you if it's because of extension incompatibilities, an unsupported PHP version, missing PHP extensions, or something else. + +### The `composer.json` File + +As mentioned above, the entire composer configuration for your Flarum site is contained inside the `composer.json` file. You can consult the [composer documentation](https://getcomposer.org/doc/04-schema.md) for a specific schema, but for now, let's go over an annotated `composer.json` from `flarum/flarum`: + +```json +{ + // This following section is mostly just metadata about the package. + // For forum admins, this doesn't really matter. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // It's a list of packages we want, and the versions for each. + // We'll discuss this shortly. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Various composer config. The ones here are sensible defaults. + // See https://getcomposer.org/doc/06-config.md for a list of options. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // If composer can find a stable (not dev, alpha, or beta) version + // of a package, it should use that. Generally speaking, production + // sites shouldn't run beta software unless you know what you're doing. + "prefer-stable": true +} +``` + +Let's focus on that `require` section. Each entry is the name of a composer package, and a version string. To read more about version strings, see the relevant [composer documentation](https://semver.org/). + +For Flarum projects, there's several types of entries you'll see in the `require` section of your root install's `flarum/core`: + +- You MUST have a `flarum/core` entry. This should have an explicit version string corresponding to the major release you want to install. For Flarum 1.x versions, this would be `^1.0`. +- You should have an entry for each extension you've installed. Some bundled extensions are included by default (e.g. `flarum/tags`, `flarum/suspend`, etc), [others you'll add via composer commands](extensions.md). Unless you have a reason to do otherwise (e.g. you're testing a beta version of a package), we recommend using an asterisk as the version string for extensions (`*`). This means "install the latest version compatible with my flarum/core". +- Some extensions / features might require PHP packages that aren't Flarum extensions. For example, you need the guzzle library to use the [Mailgun mail driver](mail.md). In these cases, the instructions for the extension/feature in question should explain which version string to use. + +## How to install Composer? + +As with any other software, Composer must first be [installed](https://getcomposer.org/download/) on the server where Flarum is running. There are several options depending on the type of web hosting you have. + +### Dedicated Web Server + +In this case you can install composer as recommended in the Composer [guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### Managed / Shared hosting + +If Composer is not preinstalled (you can check this by running `composer --version`), you can use a [manual installation](https://getcomposer.org/composer-stable.phar). Just upload the composer.phar to your folder and run `/path/to/your/php7 composer.phar COMMAND` for any command documented as `composer COMMAND`. + +:::danger + +Some articles on the internet will mention that you can use tools like a PHP shell. If you are not sure what you are doing or what they are talking about - be careful! An unprotected web shell is **extremely** dangerous. + +::: + +## How do I use Composer? + +You'll need to use Composer over the **C**ommand-**l**ine **i**nterface (CLI). Be sure you can access your server over **S**ecure **Sh**ell (SSH). + +Once you have Composer installed, you should be able to run Composer commands in your SSH terminal via `composer COMMAND`. + +:::info Optimizations + +After most commands, you'll want to run `composer dump-autoload -a`. Essentially, this caches PHP files so they run faster. + +::: diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..59a6e2328 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# Yapılandırma Dosyası + +Flarum yapılandırmasının Flarum yönetici panosu (veritabanı hariç) aracılığıyla değiştirilemeyeceği tek bir yer vardır ve bu, Flarum kurulu klasörde bulunan `config.php` dosyasıdır. + +Bu dosya küçük de olsa Flarum kurulumunuzun çalışması için çok önemli olan ayrıntıları içerir. + +Dosya varsa, Flarum'a zaten kurulu olduğunu söyler. Ayrıca Flarum'a veritabanı bilgisi ve daha fazlasını sağlar. + +Örnek bir dosyayla her şeyin ne anlama geldiğine dair hızlı bir genel bakış: + +```php + false, // sorunları gidermek için kullanılan hata ayıklama modunu etkinleştirir veya devre dışı bırakır + 'offline' => false, // site bakım modunu etkinleştirir veya devre dışı bırakır. Bu, sitenizi tüm kullanıcılar (yöneticiler dahil) için erişilemez hale getirir. + 'database' => + array ( + 'driver' => 'mysql', // veritabanı sürücüsü, yani MySQL, MariaDB... + 'host' => 'localhost', // bağlantının ana bilgisayarı, harici bir hizmet kullanılmadığı sürece çoğu durumda localhost + 'database' => 'flarum', // veritabanının adı + 'username' => 'root', // veritabanı kullanıcı adı + 'password' => '', // veritabanı şifresi + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', / veritabanındaki tablolar için önek, aynı veritabanını başka bir hizmetle paylaşıyorsanız kullanışlıdır + 'port' => '3306', // veritabanı bağlantısının portu, MySQL ile varsayılan olarak 3306'dır + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // URL kurulumu, etki alanlarını değiştirirseniz bunu değiştirmek isteyeceksiniz + 'paths' => + array ( + 'api' => 'api', // /api , API'ye gider. + 'admin' => 'admin', // /admin , yönetici paneline gider. + ), +); +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..ded88ead0 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Konsol + +Yönetici kontrol paneline ek olarak Flarum, forumunuzu terminal üzerinden yönetmenize yardımcı olmak için çeşitli konsol komutları sağlar. + +Konsolu kullanma: + +1. Flarum kurulumunuzun barındırıldığı sunucuya `ssh`ile bağlanın. +2. `cd` komutu ile `flarum` klasörüne git +3. `php flarum [command]` komutunu çalıştırın. + +## Varsayılan Komutlar + +### list + +Mevcut tüm yönetim komutlarını ve ayrıca yönetim komutlarını kullanma talimatlarını listeler. + +### help + +`php flarum help [command_name]` + +Belirli bir komut için yardım çıktısını görüntüler. + +`--format` seçeneğini kullanarak yardımın çıktısını başka formatlarda da yapabilirsiniz: + +`php flarum help --format=xml list` + +Mevcut komutların listesini görüntülemek için lütfen `list` komutunu kullanın. + +### info + +`php flarum info` + +Flarum'un çekirdeği ve yüklü uzantıları hakkında bilgi edinin. Bu, hata ayıklama sorunları için çok kullanışlıdır ve destek talep edilirken paylaşılmalıdır. + +### cache:clear + +`php flarum cache:clear` + +Oluşturulan js/css, metin biçimlendirici önbelleği ve önbelleğe alınmış çeviriler dahil olmak üzere arka uç Flarum önbelleğini temizler. Bu, uzantıları yükledikten veya kaldırdıktan sonra çalıştırılmalıdır ve sorun ortaya çıktığında bunu çalıştırmak ilk adım olmalıdır. + +### assets:publish + +`php flarum assets:publish` + +Publish assets from core and extensions (e.g. compiled JS/CSS, bootstrap icons, logos, etc). This is useful if your assets have become corrupted, or if you have switched [filesystem drivers](extend/filesystem.md) for the `flarum-assets` disk. + +### migrate + +`php flarum migrate` + +Bekleyen tüm geçişleri çalıştırır. Bu, veritabanını değiştiren bir uzantı eklendiğinde veya güncellendiğinde kullanılmalıdır. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Bir uzantı için tüm geçişleri sıfırlayın. Bu, çoğunlukla uzantı geliştiricileri tarafından kullanılır, ancak bazen, bir uzantıyı kaldırıyorsanız ve tüm verilerini veritabanından temizlemek istiyorsanız bunu çalıştırmanız gerekebilir. Lütfen bunun çalışması için söz konusu uzantının şu anda yüklü olması ancak mutlaka etkinleştirilmesi gerekmediğini unutmayın. + +### schedule:run + +`php flarum schedule:run` + +Many extensions use scheduled jobs to run tasks on a regular interval. This could include database cleanups, posting scheduled drafts, generating sitemaps, etc. If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +This command should generally not be run manually. + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +This command returns a list of scheduled commands (see `schedule:run` for more information). This is useful for confirming that commands provided by your extensions are registered properly. This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..7b17fc28e --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Docs and Translation + +## Add Documentation + +Adding documentation can help countless future Flarum users. A few ideas of what to work on: + +- User guides to help Flarum end users with some advanced Flarum features. +- More [frequently asked questions](faq.md). +- Expanded [troubleshooting](troubleshoot.md) steps. +- Step-by-step tutorials for Flarum development or installation. +- [Technical reference guides](extend/README.md) for extension developers. +- Improving literally anything else you think we should elaborate on or explain better. + +A good way to find topics to write about is to look for common questions in the [support tag](https://discuss.flarum.org/t/support) of our community. + +## Translate Flarum + +We want Flarum to be accessible to everyone, regardless of language! By contributing translations, you make it possible for many more people to enjoy Flarum. Best of all, we use user-friendly GUIs for translations, so no technical skills are necessary to help! + +Translations for Flarum core, bundled extensions, and community extensions are managed through [Weblate](https://weblate.rob006.net/projects/flarum/). + +Translations for this documentation are managed through [Crowdin](https://crowdin.com/project/flarum-docs). + +The Flarum Foundation has created the "flarum-lang" organization to support translators and ensure continuous availability of language packs. You can learn more about this by [visiting the GitHub repository](https://github.com/flarum-lang/about). + +If you want to support an existing language pack, start a new translation, or you run into issues using weblate or crowdin, it's best to [get in touch with the `flarum-lang` team](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..f6b7b0d32 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# Katkıda Bulunmak + +Flarum gelişimine katkıda bulunmak ister misiniz? Bu harika! [Bir hata raporu açmaktan](bugs.md) bir çekme isteği (PR) oluşturmaya kadar: her katkı takdir edilir ve memnuniyetle karşılanır. Flarum wouldn't be possible without our community contributions. + +Katkıda bulunmadan önce lütfen [davranış kurallarını](code-of-conduct.md) okuyun. + +Bu belge, Flarum'a kod katkısında bulunmak isteyen geliştiriciler için bir kılavuzdur. Yeni başlıyorsanız, Flarum'un nasıl çalıştığı hakkında biraz daha fazla bilgi edinmek için Uzantı belgelerindeki [Başlarken](/extend/start.md) belgelerini okumanızı öneririz. + +## Ne Üzerinde Çalışmalı + +⚡ **Have Real Impact.** There are thousands of Flarum instances, with millions of aggregate end users. By contributing to Flarum, your code will have a positive impact on all of them. + +🔮 **Shape the Future of Flarum.** We have a long backlog, and limited time. If you're willing to champion a feature or change, it's much more likely to happen, and you'll be able to enact your vision for it. Plus, our roadmap and milestones are set by our [core development team](https://flarum.org/team), and all of us started as contributors. The best road to influence is contributing. + +🧑💻 **Become a Better Engineer.** Our codebase is modern, and we heavily value good engineering and clean code. There's also a lot of interesting, challenging problems to solve regarding design, infrastructure, performance, and extensibility. Especially if you're a student or early in your career, working on Flarum is a great opportunity to build development skills. + +🎠 **It's Fun!** We really enjoy working on Flarum: there's a lot of interesting challenges and fun features to build. We also have an active community on [our forums](https://discuss.flarum.org) and [Discord server](https://flarum.org/chat). + +## Geliştirme Kurulumu + +Nelerin yapılması gerektiğine dair genel bir bakış için [Milestones](https://github.com/flarum/core/milestones) dönüm noktalarına göz atın. Başlaması nispeten kolay olması gereken sorunların bir listesi için [Good first issue](https://github.com/flarum/core/labels/Good%20first%20issue) etiketine bakın. If there's anything you're unsure of, don't hesitate to ask! All of us were just starting out once. + +Devam etmeyi ve bir şey üzerinde çalışmayı planlıyorsanız, lütfen ilgili konu hakkında yorum yapın veya önce yeni bir sorun oluşturun. Bu şekilde değerli çalışmalarınızın boşuna olmamasını sağlayabiliriz. + +Since Flarum is so extension-driven, we highly recommend [our extension docs](extend/README.md) as a reference when working on core, as well as for bundled extensions. You should start with [the introduction](extend/README.md) for a better understanding of our extension philosophy. + +## Geliştirme İş Akışı + +### Setting Up a Local Codebase + +[flarum/flarum](https://github.com/flarum/flarum) is a "skeleton" application which uses Composer to download the core package and a bunch of extensions. Source code for Flarum core, extensions, and all packages used by the aforementioned is located in the Flarum monorepo [flarum/framework](https://github.com/flarum/framework). In order to contribute to these, you'll need to fork and clone the monorepo repository locally, and then add it to your dev environment as a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com/Hello!
+ } +} +``` + +### Setting Page as Homepage + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Page Titles + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..b8af97c41 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,422 @@ +# Ön Uç Geliştirme + +This page describes how to make changes to Flarum's user interface. How to add buttons, marquees, and blinking text. 🤩 + +[Remember](/extend/start.md#architecture), Flarum's frontend is a **single-page JavaScript application**. There's no Twig, Blade, or any other kind of PHP template to speak of. The few templates that are present in the backend are only used to render search-engine-optimized content. All changes to the UI need to be made via JavaScript. + +Flarum has two separate frontend applications: + +* `forum`, the public side of your forum where users create discussions and posts. +* `admin`, the private side of your forum where, as an administrator of your forum, you configure your Flarum installation. + +They share the same foundational code, so once you know how to extend one, you know how to extend both. + +:::tip Typings! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Transpilation and File Structure + +This portion of the guide will explain the necessary file setup for extensions. Once again, we highly recommend using the [Flarum CLI](https://github.com/flarum/cli) to set up the file structure for you. That being said, you should still read this to understand what's going on beneath the surface. + +Before we can write any JavaScript, we need to set up a **transpiler**. This allows us to use [TypeScript](https://www.typescriptlang.org/) and its magic in Flarum core and extensions. + +In order to do this transpilation, you need to be working in a capable environment. No, not the home/office kind of environment – you can work in the bathroom for all I care! I'm talking about the tools that are installed on your system. You'll need: + +* Node.js and npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +This can be tricky because everyone's system is different. From the OS you're using, to the program versions you have installed, to the user access permissions – I get chills just thinking about it! If you run into trouble, ~~tell him I said hi~~ use [Google](https://google.com) to see if someone has encountered the same error as you and found a solution. If not, ask for help from the [Flarum Community](https://discuss.flarum.org) or on the [Discord chat](https://flarum.org/discord/). + +It's time to set up our little JavaScript transpilation project. Create a new folder in your extension called `js`, then pop in a couple of new files. A typical extension will have the following frontend structure: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +This is a standard JS [package-description file](https://docs.npmjs.com/files/package.json), used by npm and Yarn (Javascript package managers). You can use it to add commands, js dependencies, and package metadata. We're not actually publishing a npm package: this is simply used to collect dependencies. + +Please note that we do not need to include `flarum/core` or any flarum extensions as dependencies: they will be automatically packaged when Flarum compiles the frontends for all extensions. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) is the system that actually compiles and bundles all the javascript (and its dependencies) for our extension. To work properly, our extensions should use the [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (shown in the above example). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Importing + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Transpilation + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Asset Registration + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..19486a0fd --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Arama + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..30fef15df --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Servis Sağlayıcı + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. [Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. The most common use case for service providers is to create, modify, or replace container bindings. That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..4fe60d6aa --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Ayarlar + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..5eb3657ad --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Yavaşlatma diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..418dee766 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Başlangıç + +Flarum eklentisi mi yazmak istiyorsunuz? Doğru yere geldiniz! Bu dökümantasyon sizi bazı temel kavramlara götürecek ve ardından ilk Flarum uzantınızı sıfırdan oluşturacaksınız. + +## Architecture + +Flarum'un nasıl büyüteceğimizi anlamak için, önce Flarum'un nasıl inşa edildiğini biraz anlamamız gerekiyor. + +Flarum'un _ modern _ programlama dillerini ve araçlarını kullandığını bilin. Daha önce sadece WordPress eklentileri oluşturduysanız, kendinizi biraz yetersiz hissedebilirsiniz! Sorun Değil - yeni şeyler öğrenmek ve becerilerinizi geliştirmek için harika bir zaman. However, we would advise that you become somewhat familiar with the technologies described below before proceeding. + +Flarum is made up of three layers: + +* First, there is the **backend**. This is written in [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), and makes use of a wide array of [Laravel](https://laravel.com/) components and other packages via [Composer](https://getcomposer.org/). You'll also want to familiarize yourself with the concept of [Dependency Injection](https://laravel.com/docs/8.x/container), which is used throughout our backend. + +* Second, the backend exposes a **public API** which allows frontend clients to interface with your forum's data. This is built according to the [JSON:API specification](https://jsonapi.org/). + +* Finally, there is the default web interface which we call the **frontend**. This is a [single-page application](https://en.wikipedia.org/wiki/Single-page_application) which consumes the API. It's built with a simple React-like framework called [Mithril.js](https://mithril.js.org). + +Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the **backend**, expose that data in the **public API**, and then display it and allow users to edit it on the **frontend**. + +So... how do we extend these layers? + +## Extenders + +In order to extend Flarum, we will be using a concept called **extenders**. Extenders are *declarative* objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created). + +Every extender is different. However, they will always look somewhat similar to this: + +```php +// Register a JavaScript and a CSS file to be delivered with the forum frontend +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls. + +To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). _Everything_ you do in your extension should be done via extenders, because they are a **guarantee** we are giving to you that a future minor release of Flarum won't break your extension. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hello World + +Want to see an extender in action? The `extend.php` file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Now pay your forum a visit for a pleasant (albeit extremely obtrusive) greeting. 👋 + +For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the `extend.php` file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension! + +## Extension Packaging + +[Composer](https://getcomposer.org) is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly. + +As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice! + +During development, you can work on your extensions locally and set up a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path) to install your local copy. Create a new `packages` folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here: + +```bash +composer config repositories.0 path "packages/*" +``` + +Now let's start building our first extension. Make a new folder inside `packages` for your extension called `hello-world`. We'll put two files in it: `extend.php` and `composer.json`. These files serve as the heart and soul of the extension. + +### extend.php + +The `extend.php` file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the `Frontend` extender that you had earlier. + +### composer.json + +We need to tell Composer a bit about our package, and we can do this by creating a `composer.json` file: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": "^1.0.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** is the name of the Composer package in the format `vendor/package`. + * You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using `acme` as your vendor name. + * You should prefix the `package` part with `flarum-` to indicate that it’s a package specifically intended for use with Flarum. + +* **description** is a short one-sentence description of what the extension does. + +* **type** MUST be set to `flarum-extension`. This ensures that when someone "requires" your extension, it will be identified as such. + +* **require** contains a list of your extension's own dependencies. + * You'll want to specify the version of Flarum that your extension is compatible with here. + * This is also the place to list other Composer libraries your code needs to work. + +* **autoload** tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase. + +* **extra.flarum-extension** contains some Flarum-specific information, like your extension's display name and how its icon should look. + * **title** is the display name of your extension. + * **icon** is an object which defines your extension's icon. The **name** property is a [Font Awesome icon class name](https://fontawesome.com/icons). All other properties are used as the `style` attribute for your extension's icon. + +See [the composer.json schema](https://getcomposer.org/doc/04-schema.md) documentation for information about other properties you can add to `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Use the CLI to automatically create your extension's scaffolding: +```bash +$ flarum-cli init +``` + +::: + +### Installing Your Extension + +The final thing we need to do to get up and running is to install your extension. Navigate to the root directory of your Flarum install and run the following command: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Once that's done, go ahead and fire 'er up on your forum's Administration page, then navigate back to your forum. + +*whizzing, whirring, metal clunking* + +Woop! Hello to you too, extension! + +We're making good progress. We've learned how to set up our extension and use extenders, which opens up a lot of doors. Read on to learn how to extend Flarum's frontend. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..56124ff0e --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Deneme + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + +something
Hello World!
; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return{this.counter}
; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +{this.attrs.counter}
; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +Counter: {app.counter.getCount()}
+Hello World!{this.showContent ? ' Extra Content!' : ''}
+Hello World!
Hello World
" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. The name of the invalid field is returned as the `pointer` value. There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..97e8e6730 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Tema + +Flarum'u olabildiğince güzel hale getirmek için çok çalışmış olsak da, her topluluk muhtemelen arzu ettikleri stile uyacak bazı ince ayarlar/değişiklikler yapmak isteyecektir. + +## Yönetici Gösterge Paneli + +[Yönetici gösterge tablosu](admin.md)'nun Görünüm sayfası, forumunuzu özelleştirmeye başlamak için harika bir ilk yerdir. Burada yapabilirsin: + +- Tema renklerini seçin +- Karanlık modu ve renkli üstbilgi değiştir +- Bir logo ve favicon yükleyin (tarayıcı sekmelerinde gösterilen simge) +- Özel üstbilgiler ve altbilgiler için HTML ekleyin +- Öğelerin görüntülenme şeklini değiştirmek için [özel LESS/CSS](#css-theming) ekleyin + +## CSS Tema Oluşturma + +CSS, tarayıcılara bir web sayfasının öğelerinin nasıl görüntüleneceğini söyleyen bir stil sayfası dilidir. Renklerden yazı tiplerine, eleman boyutuna ve konumlandırmadan animasyonlara kadar her şeyi değiştirmemizi sağlar. Özel CSS eklemek, Flarum kurulumunuzu bir temayla eşleşecek şekilde değiştirmenin harika bir yolu olabilir. + +Bir CSS eğitimi bu belgesinin kapsamı dışındadır, ancak CSS'nin temellerini öğrenmek için birçok harika çevrimiçi kaynak vardır. + +:::tip + +Flarum aslında LESS kullanır, bu da değişkenlere, koşullara ve işlevlere izin vererek CSS yazmayı kolaylaştırır. + +::: + +## Uzantılar + +Flarum'un esnek [uzantı sistemi](extensions.md), Flarum'un herhangi bir parçasını pratik olarak eklemenize, çıkarmanıza veya değiştirmenize olanak tanır. Renkleri/boyutları/stilleri değiştirmenin ötesinde önemli tema değişiklikleri yapmak istiyorsanız, kesinlikle gitmenin yolu özel bir uzantıdır. Bir uzantının nasıl oluşturulacağını öğrenmek için [uzantı belgelerimize](extend/README.md) göz atın! diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..312c3e286 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Sorun Giderme + +Flarum beklendiği gibi yüklenmiyorsa veya çalışmıyorsa, yapmanız gereken ilk şey ortamınızın [sistem gereksinimlerini](install.md#sunucu-gereksinimleri) karşılayıp karşılamadığını *tekrar kontrol etmektir.* Flarum'un çalıştırması gereken bir şeyi kaçırıyorsanız, onu düzeltmeniz gerekir. If you're missing something that Flarum needs to run, you'll need to remedy that first. + +Ayrıca, [Destek forumunu](https://discuss.flarum.org/t/support) ve [sorun izleyiciyi](https://github.com/flarum/core/issues) aramak için birkaç dakikanızı ayırmalısınız. Birisi sorunu zaten bildirmiş olabilir ve bir düzeltme mevcut veya yolda. İyice araştırdıysanız ve sorunla ilgili herhangi bir bilgi bulamıyorsanız, sorun gidermeye başlamanın zamanı geldi. + +## Step 0: Activate debug mode + +:::danger Skip on Production + +These debugging tools are very useful, but can expose information that shouldn't be public. These are fine if you're on a staging or development environment, but if you don't know what you're doing, skip this step when on a production environment. + +::: + +Devam etmeden önce, Flarum'un hata ayıklama araçlarını etkinleştirmelisiniz. Basitçe bir metin düzenleyiciyle **config.php** açın, `debug` değerini `true` olarak değiştirin ve dosyayı kaydedin. Bu, Flarum'un ayrıntılı hata mesajları göstermesine neden olarak size neyin yanlış gittiğine dair bir fikir verecektir. + +Boş sayfalar görüyorsanız ve yukarıdaki değişiklik yardımcı olmuyorsa, **php.ini** yapılandırma dosyanızda `display_errors` ı `On` olarak ayarlamayı deneyin. + +## 1. Adım: Yaygın düzeltmeler + +A lot of issues can be fixed with the following: + +* Tarayıcınızın önbelleğini temizleyin +* Arka uç önbelleğini [`php flarum cache:clear`](console.md) ile temizleyin. +* Veritabanınızın [`php flarum migrate`](console.md) ile güncellendiğinden emin olun. +* Yönetici panonuzdaki [e-posta yapılandırmasının](mail.md) doğru olduğundan emin olun: geçersiz e-posta yapılandırması kayıt olurken, parolayı sıfırlarken, e-postaları değiştirirken ve bildirim gönderirken hatalara neden olur. +* `config.php` dosyanızın doğru olup olmadığını kontrol edin. Örneğin, doğru `url` nin kullanıldığından emin olun. +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +Ayrıca önemli hiçbir şeyin yerinde olmadığından emin olmak için [`php flarum info`](console.md) çıktısına da göz atmak isteyeceksiniz. + +## 2. Adım: Sorunu yeniden oluşturun + +Sorunun yeniden oluşmasını sağlamaya çalışın. Gerçekleştiğinde ne yaptığınıza dikkat edin. Her seferinde mi yoksa sadece ara sıra mı oluyor? Sorunu etkileyebileceğini düşündüğünüz bir ayarı veya bir şeyleri yaptığınız sırayı değiştirmeyi deneyin. Bazı koşullarda olurken diğerleri olmuyor mu? + +Yakın zamanda bir uzantı eklediyseniz veya güncellediyseniz, sorunun çözülüp çözülmediğini görmek için geçici olarak devre dışı bırakmalısınız. Tüm uzantılarınızın, çalıştırdığınız Flarum sürümüyle kullanılmak üzere tasarlandığından emin olun. Eski uzantılar, çeşitli sorunlara neden olabilir. + +Yol boyunca bir yerlerde sorununuza neyin sebep olduğu hakkında bir fikir edinebilir ve bunu düzeltmenin bir yolunu bulabilirsiniz. Ancak bu olmasa bile, hata raporunuzu doldurduktan sonra, neler olup bittiğini anlamamıza yardımcı olacak birkaç değerli ipucuyla karşılaşacaksınız. + +## 3. Adım: Bilgi toplayın + +Sorunu çözmek için yardıma ihtiyacınız olacak gibi görünüyorsa, veri toplama konusunda ciddi olmanın zamanı geldi. Aşağıdaki yerlerde hata mesajlarını veya sorunla ilgili diğer bilgileri arayın: + +* Asıl sayfada görüntülenir +* Tarayıcı konsolunda görüntülenir (Chrome: Diğer araçlar -> Geliştirici Araçları -> Konsol) +* `/var/log/nginx/error.log`) +* PHP-FPM'nin hata günlüğüne kaydedilir (ör. `/var/log/php7.x-fpm.log`) +* Flarum tarafından kaydedildi (`storage/logs/flarum.log`) + +Herhangi bir mesajı bir metin dosyasına kopyalayın ve hatanın *ne zaman* oluştuğu, o sırada *ne yaptığınız* vb. Hakkında birkaç not alın. Sorunun meydana geldiği ve oluşmadığı koşullar hakkında derlemiş olabileceğiniz tüm bilgileri eklediğinizden emin olun. Sunucu ortamınız hakkında olabildiğince fazla bilgi ekleyin: İşletim sistemi sürümü, web sunucusu sürümü, PHP sürümü ve işleyici, vb. + +## 4. Adım: Bir rapor hazırlayın + +Sorunla ilgili tüm bilgileri topladıktan sonra bir hata raporu vermeye hazırsınız. Lütfen [Hataları Bildirme](bugs.md) ile ilgili talimatları uygulayın. + +Raporunuzu doldurduktan sonra sorunla ilgili yeni bir şey keşfederseniz, lütfen bu bilgiyi orijinal yayınınızın altına ekleyin. Sorunu kendi başınıza çözmüş olsanız bile rapor vermek iyi bir fikirdir, çünkü diğer kullanıcılar da çözümünüzden faydalanabilir. Sorun için geçici bir çözüm bulduysanız, bundan da bahsettiğinizden emin olun. \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..74eb08c71 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Güncelleme + +## From the Admin Dashboard + +:::bilgi + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +Flarum'u güncellemek için [Composer](https://getcomposer.org) kullanmanız gerekir. Eğer aşina değilseniz (Flarum'u kurmak için buna ihtiyacınız vardır), ne olduğu ve nasıl kurulacağı hakkında bilgi için [kılavuzumuzu](composer.md) okuyun. + +Ana sürümler arasında güncelleme yapıyorsanız (ör. <=0.1.0 - 1.x.x, 1.x.x - 2.x.x, ...), genel yükseltme adımlarını çalıştırmadan önce uygun "ana sürüm güncelleme kılavuzunu" okuduğunuzdan emin olun. + +## Genel Adımlar + +**1. Adım:** Tüm uzantılarınızın, yüklemeye çalıştığınız Flarum sürümüyle uyumlu sürümleri olduğundan emin olun. Bu yalnızca ana sürümler için gereklidir (örneğin, uzantılarınızın önerilen sürümü izlediğini varsayarsak, v1.0.0'dan v1.1.0'a yükseltme yapıyorsanız muhtemelen bunu kontrol etmeniz gerekmez). Bunu, uzantının [Tartışma konusuna](https://discuss.flarum.org/t/extensions) bakarak, [Packagist](http://packagist.org/)'te arayarak veya [Extiverse](https://extiverse.com) gibi veritabanlarını kontrol ederek bilgi alabilirsiniz. Güncellemeden önce uyumsuz uzantıları kaldırmanız (yalnızca devre dışı bırakmanız değil) gerekir. Lütfen uzantı geliştiricilerine karşı sabırlı olun! + +**2. Adım:** `composer.json` dosyanıza bir göz atın. Uzantıların veya kitaplıkların belirli sürümlerini gerektirecek bir nedeniniz yoksa, `flarum/core` dışındaki her şeyin sürüm dizesini `*` olarak ayarlamalısınız ((`flarum/tags dahil) `, `flarum/bahsetmeler` ve diğer paket uzantılar.) `flarum/core` öğesinin `*` olarak AYARLANMADIĞINDAN emin olun. Belirli bir Flarum sürümünü hedefliyorsanız, `flarum/core` öğesini buna ayarlayın (ör. `"flarum/core": "v0.1.0-beta.16`). Yalnızca en son sürümü istiyorsanız, `"flarum/core": "^1.0"` kullanın. + +**3. Adım:** Yerel kurulumunuz [yerel genişleticiler](extenders.md) kullanıyorsa, bunların Flarum'daki değişikliklerle güncel olduğundan emin olun. + +**4. Adım:** Güncellemeden önce yönetici kontrol panelinde üçüncü taraf uzantıları devre dışı bırakmanızı öneririz. Bu kesinlikle gerekli değildir, ancak sorunlarla karşılaşırsanız hata ayıklamayı kolaylaştıracaktır. + +**Adım 5:** PHP sürümünüzün yükseltmeye çalıştığınız Flarum sürümü tarafından desteklendiğinden ve Composer 2'yi (`composer --version)` kullandığınızdan emin olun. + +**6. Adım:** Son olarak, güncellemek için şunu çalıştırın: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Adım 7:** Varsa, PHP işleminizi ve opcache'nizi yeniden başlatın. + +## Ana Sürüm Güncelleme Kılavuzları + +### Beta'dan (<=0.1.0) Kararlı v1'e (^1.0.0) güncelleme + +1. Yukarıdaki 1-5 adımlarını uygulayın. +2. `Composer.json`'da tüm paketlenmiş uzantıların (`flarum/tags`, `flarum/bahsetme`, `flarum/likes` vb.) sürüm dizelerini değiştirin. `^0.1.0` ile `*` arasında değişti. +3. `composer.json` içindeki `flarum/core` sürüm dizesini `^0.1.0`'den `^1.0`'e değiştirin. +4. `composer.json` dosyanızdan `"minimum-stability": "beta",` satırını kaldırın +5. Yukarıdaki 6. ve 7. adımları uygulayın. + +## Sorun Giderme + +Flarum'u güncellerken hatalarla karşılaşabileceğiniz 2 ana yer vardır: Güncelleme komutunu çalıştırırken veya güncellemeden sonra foruma erişirken. + +### Güncelleme Sırasında Oluşan Hatalar + +Burada, Flarum'u güncellemeye çalışırken sık karşılaşılan birkaç sorun türünü inceleyeceğiz. + +--- + +Çıktı kısaysa ve şunları içeriyorsa: + +``` +Nothing to modify in lock file +``` + +Veya `flarum/core`'u güncellenmiş bir paket olarak listelemiyor ve en son flarum sürümünü kullanmıyorsunuz: + +- Yukarıdaki 2. adımı tekrar gözden geçirin, tüm üçüncü taraf uzantılarının sürüm dizelerinde bir yıldız işaretine sahip olduğundan emin olun. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +If you are unable to access your forum after updating, follow our [troubleshooting instructions](troubleshoot.md). diff --git a/i18n/vi/docusaurus-plugin-content-docs/current.json b/i18n/vi/docusaurus-plugin-content-docs/current.json index 23152dfb5..15c22ad1e 100644 --- a/i18n/vi/docusaurus-plugin-content-docs/current.json +++ b/i18n/vi/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Tiếp theo", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Tài liệu nội bộ", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..62d814c21 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# Về Flarum + +Flarum là một nền tảng thảo luận đơn giản thú vị cho trang web của bạn. Nó nhanh chóng, miễn phí và dễ sử dụng, với tất cả các tính năng bạn cần để điều hành một cộng đồng thành công. Nó cũng cực kỳ có thể mở rộng, cho phép khả năng tùy chỉnh cao nhất. + + + +## Mục tiêu + +Flarum là sự kế thừa kết hợp của [esoTalk](https://github.com/esotalk/esoTalk) và [FluxBB](https://fluxbb.org). Nó được thiết kế để: + +* **Nhanh chóng và đơn giản.** Không lộn xộn, không cồng kềnh, không phụ thuộc phức tạp. Flarum được xây dựng bằng PHP để triển khai nhanh chóng và dễ dàng. Giao diện được cung cấp bởi [Mithril](https://mithril.js.org), một khung JavaScript hiệu quả với một dấu ấn nhỏ. + +* **Đẹp và nhanh nhạy.** Đây là phần mềm diễn đàn dành cho con người. Flarum được thiết kế cẩn thận để nhất quán và trực quan trên các nền tảng, ngay từ đầu. + +* **Mạnh mẽ và có thể mở rộng.** Tùy chỉnh, mở rộng và tích hợp Flarum cho phù hợp với cộng đồng của bạn. Kiến trúc của Flarum rất linh hoạt, với [API tiện ích mở rộng mạnh mẽ](/extend/README.md). + +* **Miễn phí và mở.** Flarum được phát hành theo [giấy phép MIT](https://github.com/flarum/flarum/blob/master/LICENSE). + +Bạn có thể đọc thêm về [triết lý và giá trị của chúng tôi đối với Flarum tại đây](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values). + +## Trợ giúp dự án Flarum + +Flarum là phần mềm [miễn phí, mã nguồn mở](https://github.com/flarum/core), được duy trì và quản lý bởi các tình nguyện viên. Chúng tôi dựa vào sự đóng góp của cộng đồng để giúp chúng tôi cải thiện và mở rộng Flarum. + +🧑💻 Nếu bạn là nhà phát triển, hãy xem xét [đóng góp vào các tiện ích mở rộng cốt lõi hoặc đi kèm của Flarum](contributing.md). Đây là **cách** hiệu quả nhất để trợ giúp Flarum và công việc của bạn có thể có nhiều tác động: có hàng nghìn trang web Flarum trên mạng, với tổng số hàng triệu người dùng cuối. + +🧩 Nếu thiếu tính năng bạn đang tìm kiếm hoặc ý tưởng chủ đề bạn có, [viết một phần mở rộng tùy chỉnh](extend/README.md) sẽ làm cho Flarum tốt hơn nhiều cho bạn và những người khác. + +✒️ Nếu bạn có kinh nghiệm viết kỹ thuật, hãy đóng góp cho [tài liệu của chúng tôi](https://github.com/flarum/docs/issues) có thể giúp người dùng, quản trị viên và nhà phát triển trong tương lai tận dụng tối đa Flarum. + +🌐 Nếu bạn thông thạo được nhiều ngôn ngữ, bạn có thể [đóng góp bản dịch](extend/language-packs.md) để giúp Flarum tiếp cận đến được nhiều người trên thế giới hơn. + +💸 Flarum Foundation không kiếm tiền từ Flarum, nhưng có hóa đơn thanh toán. Các khoản đóng góp qua [Nhà tài trợ GitHub](https://github.com/sponsors/flarum) hoặc [OpenCollective](https://opencollective.com/flarum) luôn luôn đã nhận một cách biết ơn. Trước đây, chúng tôi cũng đã có thể hỗ trợ tài chính cho một số nhà phát triển cốt lõi của mình, để họ có thể làm việc bán thời gian trên Flarum. Điều này sẽ không thể thực hiện được nếu không có sự hỗ trợ tài chính của bạn. + +🧑🤝🧑 Tham gia [cộng đồng của chúng tôi](https://discuss.flarum.org) để nói về sự phát triển của Flarum, nhận trợ giúp về phiên bản của bạn hoặc gặp gỡ những người thú vị! Nếu bạn có kinh nghiệm với Flarum, bạn cũng có thể giúp đỡ những người mới bắt đầu! + +🐛 Nếu có một lỗi nào đó đang làm phiền bạn hoặc bạn nảy ra ý tưởng về tính năng, chúng tôi không thể biết về nó trừ khi bạn cho chúng tôi biết! Chúng tôi theo dõi các lỗi, đề xuất và kế hoạch phát triển trong tương lai [thông qua các vấn đề GitHub](https://github.com/flarum/core/issues). Nếu đã có một vấn đề đang mở, việc thêm lượt thích và thông tin bổ sung (mang tính xây dựng) có thể rất hữu ích! + +📣 Và nếu bạn thích Flarum, hãy cân nhắc viết blog/tweet/nói về nó! Nhiều người biết đến Flarum hơn dẫn đến nhiều người tương tác với Flarum hơn, và do đó có nhiều hoạt động hơn, tiện ích mở rộng tốt hơn và phát triển nhanh hơn. + +Flarum sẽ không thể thực hiện được nếu không có cộng đồng hiện tượng của chúng tôi. Nếu bạn muốn đóng góp, hãy xem tài liệu [đóng góp của nhà phát triển](contributing.md) và [đóng góp khác](contributing-docs-translations.md) của chúng tôi để biết thêm thông tin. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..b3fae602f --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# Trang tổng quan quản trị + +Bảng điều khiển quản trị Flarum là một giao diện thân thiện với người dùng để quản lý diễn đàn của bạn. Nó chỉ khả dụng cho người dùng trong nhóm "Quản trị viên". Để truy cập trang Quản trị, nhấn vào **Tên** của bạn ở trên cùng bên phải của màn hình và chọn **Trang quản trị**. + +Bảng điều khiển dành cho quản trị viên gồm các phần sau: +- **Trang tổng quan** - Hiển thị Trang tổng quan quản trị chính, chứa số liệu thống kê và thông tin có liên quan khác. +- **Cơ bản** - Hiển thị các tùy chọn để đặt các chi tiết cơ bản của diễn đàn như Tên, Mô tả và Biểu ngữ chào mừng. +- **Email** - Cho phép bạn định cấu hình cài đặt E-Mail của mình. Tham khảo [tại đây](https://docs.flarum.org/mail) để biết thêm thông tin. +- **Quyền** - Hiển thị các quyền cho từng nhóm người dùng và cho phép bạn định cấu hình phạm vi toàn cầu và phạm vi cụ thể. +- **Giao diện** - Cho phép bạn tùy chỉnh màu sắc, thương hiệu của diễn đàn và thêm CSS bổ sung để tùy chỉnh. +- **Người dùng** - Cung cấp cho bạn danh sách được phân trang gồm tất cả người dùng trong diễn đàn và cấp cho bạn khả năng chỉnh sửa người dùng hoặc thực hiện các hành động quản trị. + +Ngoài các phần được đề cập ở trên, Trang tổng quan quản trị cũng cho phép bạn quản lý các Tiện ích mở rộng của mình (bao gồm các tiện ích mở rộng cốt lõi như Thẻ) trong phần _Tính năng_. Các tiện ích mở rộng sửa đổi chủ đề diễn đàn hoặc cho phép bạn sử dụng nhiều ngôn ngữ được phân loại trong phần _Chủ đề_ và _Ngôn ngữ_ tương ứng. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..4736c745c --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Báo cáo lỗi + +:::danger Lỗ hổng bảo mật + +Nếu bạn phát hiện ra lỗ hổng bảo mật trong Flarum, vui lòng tuân theo[chính sách bảo mật](https://github.com/flarum/core/security/policy) của chúng tôi để chúng tôi có thể giải quyết kịp thời. + +::: + +Cảm ơn bạn đã giúp chúng tôi kiểm tra Flarum. Chúng tôi rất vui khi có bạn trong nhóm! Chúng tôi cần những người có thể *kiên nhẫn khắc phục sự cố* và *thông báo rõ ràng*. Như bạn có thể biết, báo cáo lỗi tốt cần một chút thời gian và nỗ lực. Nếu bạn ổn với điều đó, thì hãy bắt đầu! + +## Trùng lặp + +Đã tìm thấy một lỗi? Tuyệt vời! Chúng tôi rất muốn nghe về nó — nhưng trước tiên, bạn nên kiểm tra xung quanh để đảm bảo rằng bạn không lãng phí thời gian vào một vấn đề đã biết: + +- Tìm kiếm trong [Diễn đàn hỗ trợ](https://discuss.flarum.org/t/support) của chúng tôi để xem liệu nó đã được báo cáo chưa. +- Chúng tôi có thể đang tìm cách khắc phục, vì vậy hãy tìm kiếm trong [trình theo dõi sự cố](https://github.com/flarum/core/issues) của chúng tôi. + +Nếu bạn đã tìm kiếm *ỹ lưỡng* và ra về tay không, chúng tôi sẽ hoan nghênh báo cáo của bạn. Nếu đó chỉ là một vấn đề đơn giản (ví dụ: một từ sai chính tả hoặc trục trặc đồ họa), hãy chuyển sang đoạn tiếp theo. Nhưng nếu bạn thấy lỗi hoặc một cái gì đó rõ ràng bị hỏng, chúng tôi sẽ cần bạn thu thập một số thông tin trước. Vui lòng xem hướng dẫn [Gỡ rối](troubleshoot.md) của chúng tôi và làm theo hướng dẫn tại đó. Thu thập càng nhiều thông tin càng tốt! + +## Báo cáo + +Chúng tôi theo dõi các vấn đề trên GitHub. Đảm bảo rằng bạn mở sự cố của mình trong [kho lưu trữ chính xác](https://github.com/flarum) và điền vào tất cả thông tin trong mẫu Báo cáo lỗi. + +Nếu bạn có thể, hãy kiểm tra xem sự cố có thể tái tạo được bằng phiên bản Flarum mới nhất hay không. Nếu bạn đang sử dụng phiên bản phát hành trước hoặc phiên bản phát triển, vui lòng cho biết phiên bản cụ thể mà bạn đang sử dụng. + +Hãy nhớ rằng: mục tiêu của báo cáo lỗi là giúp chúng tôi dễ dàng sao chép lỗi và sửa chữa nó. Bạn có thể muốn đọc [bài viết này](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) để biết một số mẹo hữu ích về cách viết báo cáo lỗi hiệu quả. Nó **bắt buộc** bạn phải mô tả rõ ràng các bước cần thiết để tái tạo sự cố mà bạn đang gặp phải. Các vấn đề không có bước tái tạo rõ ràng sẽ không được xử lý. Nếu một vấn đề có nhãn "cần xác minh" không nhận được thêm thông tin nào từ tác giả của vấn đề trong hơn 5 ngày, nó sẽ bị đóng. + +Khi bạn đã đăng báo cáo của mình, chúng tôi đề nghị bạn *theo dõi cuộc thảo luận* và kiên nhẫn chờ đợi. Chúng tôi có thể cần hỏi thêm chi tiết hoặc làm rõ; nhưng chúng tôi luôn có nhiều việc phải làm và có thể mất một thời gian trước khi chúng tôi có thể cung cấp cho báo cáo của bạn thời gian xứng đáng. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..e13083f28 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Quy tắc ứng xử + +### _Chào bạn đến với Cộng đồng Flarum!_ + +... Và cảm ơn vì đã tham gia cùng chúng tôi! Chúng tôi rất hào hứng với Flarum và luôn vui mừng gặp gỡ những người có cùng cảm nhận. Chúng tôi muốn *mọi người* tận dụng tối đa Flarum và cộng đồng Flarum, vì vậy chúng tôi yêu cầu bạn đọc và làm theo các nguyên tắc này. Những điều này áp dụng cho dù bạn đang sử dụng diễn đàn của chúng tôi, trò chuyện Discord, giao tiếp trên GitHub hoặc bất kỳ hình thức giao tiếp nào khác mà không có cộng đồng Flarum. + +### Trên tất cả, hãy trở nên tuyệt vời! + +Tất cả chúng ta ở đây để nói về Flarum và cùng nhau làm việc để biến nó trở thành một ứng dụng tốt hơn nữa. Phê bình các ý kiến (tất nhiên bằng các lập luận hợp lý) là một phần quan trọng của điều đó. Nhưng đừng để bị cuốn trôi và lao vào các cuộc tấn công cá nhân, bởi vì sự tiêu cực chỉ cản đường. Chúng tôi yêu cầu bạn tránh những điều sau: + +- Ngôn ngữ xúc phạm hoặc lăng mạ, cũng như bất kỳ loại ngôn từ kích động thù địch nào +- Các bài đăng nhằm quấy rối, mạo danh hoặc bôi nhọ người khác +- Xóa nội dung đã đăng không cần thiết +- Cố gắng lạm dụng hoặc tiết lộ thông tin cá nhân của người khác +- Nội dung khiêu dâm hoặc khiêu dâm +- Thư rác, bài đăng lừa đảo và bất kỳ hành động nào nhằm làm xấu mặt trang web này +- Thảo luận về vi phạm bản quyền phần mềm và các chủ đề tương tự + +*Tất cả những điều trên là cơ sở để người kiểm duyệt hành động.* Nếu bạn gặp vấn đề với một thành viên khác, chúng tôi yêu cầu bạn không tự mình đối mặt với họ. Nếu là trên diễn đàn, vui lòng sử dụng lệnh *Báo cáo* trên bài đăng được đề cập, sau đó giao cho nhân viên xử lý tình huống. Otherwise, report the violation using our [contact page](https://flarum.org/foundation/contact), option Legal. + +Người kiểm duyệt của chúng tôi có thể chỉnh sửa hoặc xóa bất kỳ nội dung nào gây khó chịu hoặc làm gián đoạn luồng giao tiếp. Các hành vi vi phạm nghiêm trọng hoặc nhiều lần có thể dẫn đến việc tạm ngưng tài khoản của người dùng vi phạm. Vì vậy, bạn biết đấy, *hãy thật tuyệt*. 😎 + +### Hãy tự nghe + +Bạn muốn bắt đầu một cuộc thảo luận mới? Trước tiên, hãy nhớ đọc [Câu hỏi thường gặp của chúng tôi](faq.md) và nhấp vào các liên kết để đảm bảo bạn được thông báo đầy đủ về dự án. Sau đó, dành thời gian duyệt qua diễn đàn, tự làm quen với [hệ thống thẻ](https://discuss.flarum.org/tags) và thực hiện một vài tìm kiếm cho các từ khóa liên quan đến chủ đề của bạn: *có thể ai đó đã bắt đầu thảo luận về nó!* + +Khi bạn chắc chắn rằng mình đã sẵn sàng để bắt đầu một cuộc thảo luận, hãy ghi nhớ những điểm sau: + +- Đặt cho nó một tiêu đề tốt! Bạn sẽ nhận được kết quả tốt nhất nếu tiêu đề của bạn thể hiện rõ điều bạn muốn nói. +- Chọn (các) thẻ phù hợp. Điều này sẽ làm tăng khả năng bài viết của bạn sẽ được đọc và trả lời kịp thời. +- *Đừng* đăng nhiều lần về cùng một chủ đề, vì làm như vậy sẽ có tác dụng ngược lại. +- If not using a tag set aside for multilingual use, *post in English only.* We can't help you if we don't understand your posts. +- Hãy nhớ rằng, bạn không cần phải ký vào các bài viết của mình. Chúng tôi có hồ sơ của bạn để cho chúng tôi biết bạn là ai. + +Hãy cố gắng giúp chúng tôi giữ mọi thứ ngăn nắp. Thời gian dành cho việc thu dọn là thời gian mà chúng tôi không thể dành để tìm hiểu bạn, thảo luận các vấn đề của bạn và nói về Flarum. Và đó, sau tất cả, là những gì tất cả chúng ta ở đây để làm! + +### Thực hiện đếm câu trả lời của bạn + +Bạn đang dành thời gian để tham gia vào một cuộc thảo luận, với hy vọng rằng những người khác sẽ đọc ý tưởng của bạn và xem xét chúng. Vì vậy, tại sao không nỗ lực để làm cho câu trả lời của bạn đáng đọc? + +- Đừng trả lời một tiêu đề. Hãy dành chút thời gian để *đọc* OP và ít nhất *quét* phần còn lại của cuộc trò chuyện trước. +- Hãy tự hỏi bản thân xem câu trả lời của bạn có bổ sung vào cuộc thảo luận hay không. Nếu không, hãy suy nghĩ kỹ hơn trước khi đăng. +- Tránh đưa ra những bài viết dài một từ chỉ để đồng ý với ai đó; bạn có thể sử dụng nút "Thích" cho việc đó. +- Tránh tạo nhiều bài viết liên tiếp khi một bài đã đủ. Đây là một diễn đàn, không phải một phòng trò chuyện. +- Nếu câu trả lời của bạn có khả năng làm chuyển hướng tiến trình của cuộc thảo luận, thay vào đó, hãy cân nhắc bắt đầu một cuộc thảo luận mới. +- Thay vào đó, nếu bạn chỉ muốn đăng một chút vô nghĩa như một bài kiểm tra, vui lòng thực hiện việc đó trong thẻ [Test Posting](https://discuss.flarum.org/t/sandbox). +- Đảm bảo rằng câu trả lời của bạn cung cấp phản hồi và hỗ trợ mang tính xây dựng để tạo ra một cộng đồng hòa nhập. + +Sẽ không ai phàn nàn về những trò đùa không thường xuyên hoặc nhận xét thông minh. Chúng tôi muốn giữ cho tâm trạng nhẹ nhàng! Nhưng để giữ cho mọi thứ hiệu quả, chúng tôi yêu cầu bạn cố gắng tránh hoàn toàn việc thảo luận bị lệch. + +> Cảm ơn Dominion vì sự giúp đỡ của anh ấy trong việc đưa các nguyên tắc này lại với nhau. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..c92ac175a --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum sử dụng một chương trình có tên là [Composer](https://getcomposer.org) để quản lý các phần phụ thuộc và tiện ích mở rộng của nó. Bạn sẽ cần sử dụng trình soạn nhạc nếu bạn muốn: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +Hướng dẫn này được cung cấp dưới dạng giải thích ngắn gọn về Composer. Chúng tôi thực sự khuyên bạn nên tham khảo [tài liệu chính thức](https://getcomposer.org/doc/00-intro.md) để biết thêm thông tin. + +:::tip Shared Hosting + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## Composer là gì? + +> Composer là một công cụ để quản lý sự phụ thuộc trong PHP. Nó cho phép bạn khai báo các thư viện mà dự án của bạn phụ thuộc vào và nó sẽ quản lý (cài đặt/cập nhật) chúng cho bạn. - [Giới thiệu Composer](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Mỗi cài đặt Flarum chủ yếu bao gồm lõi Flarum và một tập hợp các [tiện ích mở rộng](extensions.md). Mỗi cái trong số này có các phụ thuộc và bản phát hành riêng của nó. + +Trước đây, các khuôn khổ diễn đàn sẽ quản lý các tiện ích mở rộng bằng cách yêu cầu người dùng tải lên các tệp zip có mã tiện ích mở rộng. Điều đó có vẻ đơn giản, nhưng các vấn đề nhanh chóng trở nên rõ ràng: + +- Tải lên các tệp zip ngẫu nhiên từ internet có xu hướng là một ý tưởng tồi. Việc yêu cầu các tiện ích mở rộng được tải xuống từ một nguồn trung tâm như [ Packagist ](https://packagist.org/) khiến việc spam mã độc trở nên tẻ nhạt hơn và đảm bảo rằng mã nguồn có sẵn trên GitHub cho phần mở rộng miễn phí/công khai. +- Giả sử Tiện ích mở rộng A yêu cầu v4 của một số thư viện và Tiện ích mở rộng B yêu cầu v5 của cùng thư viện đó. Với giải pháp dựa trên zip, một trong hai phần phụ thuộc có thể ghi đè lên phần còn lại, gây ra tất cả các loại vấn đề không nhất quán. Hoặc cả hai sẽ cố gắng chạy cùng một lúc, điều này sẽ khiến PHP gặp sự cố (bạn không thể khai báo cùng một lớp hai lần). +- Các tệp zip có thể gây ra rất nhiều đau đầu nếu cố gắng tự động hóa việc triển khai, chạy các bài kiểm tra tự động hoặc mở rộng quy mô đến nhiều nút máy chủ. +- Không có cách nào tốt để đảm bảo rằng các phiên bản tiện ích mở rộng xung đột không thể được cài đặt hoặc phiên bản PHP hệ thống và các yêu cầu về tiện ích mở rộng được đáp ứng. +- Chắc chắn, chúng tôi có thể nâng cấp các tiện ích mở rộng bằng cách thay thế tệp zip. Nhưng nâng cấp lõi Flarum thì sao? Và làm thế nào chúng tôi có thể đảm bảo rằng các tiện ích mở rộng có thể khai báo phiên bản lõi nào mà chúng tương thích với? + +Composer xử lý tất cả những vấn đề này và hơn thế nữa! + +## Flarum và Composer + +Khi bạn vào [cài đặt Flarum](install.md#installing), bạn thực sự đang làm 2 điều: + +1. Tải xuống "bộ khung" bản soạn sẵn cho Flarum. Điều này bao gồm tệp `index.php` xử lý các yêu cầu web, tệp `flarum` cung cấp CLI và một loạt cấu hình máy chủ web và thiết lập thư mục. Điều này được lấy từ [`flarum/flarum` kho lưu trữ github](https://github.com/flarum/flarum) và không thực sự chứa bất kỳ mã nào cần thiết để Flarum chạy. +2. Cài đặt các gói `composer` cần thiết cho Flarum, cụ thể là lõi Flarum và một số phần mở rộng đi kèm. Chúng được gọi bởi các tệp `index.php` và `flarum` từ bước 1 và là phần triển khai của Flarum. Chúng được chỉ định trong tệp `composer.json` có trong khung. + +Khi bạn muốn cập nhật Flarum hoặc thêm/cập nhật/xóa phần mở rộng, bạn sẽ thực hiện việc này bằng cách chạy các lệnh `composer`. Mỗi lệnh là khác nhau, nhưng tất cả các lệnh đều tuân theo cùng một quy trình chung: + +1. Cập nhật tệp `composer.json` để thêm/xóa/cập nhật gói. +2. Thực hiện một loạt phép toán để có được phiên bản tương thích mới nhất của mọi thứ nếu có thể, hoặc tìm ra lý do tại sao việc sắp xếp được yêu cầu là không thể. +3. Nếu mọi thứ hoạt động, hãy tải xuống phiên bản mới của mọi thứ cần được cập nhật. Nếu không, hãy hoàn nguyên các thay đổi của `composer.json` + +Khi chạy các lệnh `composer.json`, hãy đảm bảo chú ý đến kết quả đầu ra. Nếu có lỗi, nó có thể sẽ cho bạn biết liệu đó có phải là do sự không tương thích của tiện ích mở rộng, phiên bản PHP không được hỗ trợ, thiếu các tiện ích mở rộng PHP hay do nguyên nhân khác. + +### Tệp `composer.json` + +Như đã đề cập ở trên, toàn bộ cấu hình trình soạn nhạc cho trang web Flarum của bạn được chứa bên trong tệp `composer.json`. Bạn có thể tham khảo [tài liệu về composer](https://getcomposer.org/doc/04-schema.md) để biết một giản đồ cụ thể, nhưng bây giờ, hãy xem qua một trình soạn nhạc `composer.json` từ `flarum/flarum`: + +```json +{ + // Phần sau đây chủ yếu chỉ là siêu dữ liệu về gói. + // Đối với quản trị viên diễn đàn, điều này không thực sự quan trọng. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // Đó là danh sách các gói chúng tôi muốn và các phiên bản cho mỗi gói. + // Chúng ta sẽ thảo luận về vấn đề này ngay sau đây. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Nhiều cấu hình composer khác nhau. Những cái ở đây là mặc định hợp lý. + // Xem https://getcomposer.org/doc/06-config.md để biết danh sách các tùy chọn. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // Nếu nhà soạn nhạc có thể tìm thấy phiên bản ổn định (không phải dev, alpha hoặc beta) + // của một gói, nó sẽ sử dụng cái đó. Nói chung, sản xuất + // các trang web không nên chạy phần mềm beta trừ khi bạn biết mình đang làm gì. + "prefer-stable": true +} +``` + +Hãy tập trung vào phần `request` đó. Mỗi mục nhập là tên của một gói composer và một chuỗi phiên bản. Để đọc thêm về chuỗi phiên bản, hãy xem [tài liệu về composer](https://semver.org/) có liên quan. + +Đối với các dự án Flarum, có một số loại mục nhập bạn sẽ thấy trong phần `require` của `flarum /core` cài đặt gốc của bạn: + +- Bạn PHẢI có mục nhập `flarum/core`. Điều này phải có một chuỗi phiên bản rõ ràng tương ứng với bản phát hành chính mà bạn muốn cài đặt. Đối với các phiên bản Flarum 1.x, đây sẽ là `^1.0`. +- Bạn sẽ có một mục nhập cho mỗi tiện ích mở rộng mà bạn đã cài đặt. Một số tiện ích mở rộng đi kèm được bao gồm theo mặc định (ví dụ: `flarum/tags`, `flarum/pause`, v.v.), [những tiện ích khác mà bạn sẽ thêm qua lệnh của composer](extensions.md). Trừ khi bạn có lý do để làm khác (ví dụ: bạn đang thử nghiệm phiên bản beta của một gói), chúng tôi khuyên bạn nên sử dụng dấu hoa thị làm chuỗi phiên bản cho các tiện ích mở rộng (`*`). Điều này có nghĩa là "cài đặt phiên bản mới nhất tương thích với flarum/core của tôi". +- Một số tiện ích mở rộng / tính năng có thể yêu cầu các gói PHP không phải là tiện ích mở rộng Flarum. Ví dụ: bạn cần thư viện guzzle để sử dụng [trình điều khiển thư Mailgun](mail.md). Trong những trường hợp này, hướng dẫn cho tiện ích mở rộng/tính năng được đề cập phải giải thích chuỗi phiên bản nào được sử dụng. + +## Làm thế nào để cài đặt Composer? + +Như với bất kỳ phần mềm nào khác, Composer trước tiên phải được [cài đặt](https://getcomposer.org/download/) trên máy chủ nơi Flarum đang chạy. Có một số tùy chọn tùy thuộc vào loại lưu trữ web bạn có. + +### Máy chủ web chuyên dụng + +Trong trường hợp này, bạn có thể cài đặt composer theo khuyến nghị trong [hướng dẫn](https://getcomposer.org/doc/00-intro.md#system-requirements) Composer. + +### Managed / Shared hosting + +Nếu Composer chưa được cài đặt sẵn (bạn có thể kiểm tra điều này bằng cách chạy `composer --version`), bạn có thể sử dụng [hướng dẫn sử dụng cài đặt](https://getcomposer.org/composer-stable.phar). Chỉ cần tải composer.phar lên thư mục của bạn và chạy `/path/to/your/php7 composer.phar COMMAND` cho bất kỳ lệnh nào được ghi dưới dạng `composer COMMAND`. + +:::danger + +Một số bài báo trên internet sẽ đề cập rằng bạn có thể sử dụng các công cụ như PHP shell. Nếu bạn không chắc mình đang làm gì hoặc họ đang nói về điều gì - hãy cẩn thận! Trình bao web không được bảo vệ là **cực kỳ** nguy hiểm. + +::: + +## Cách sử dụng Composer? + +Bạn sẽ cần sử dụng Composer trên **C**ommand-**l**ine **i**nterface (CLI). Đảm bảo bạn có thể truy cập máy chủ của mình qua **S**ecure**Sh**ell (SSH). + +Sau khi bạn đã cài đặt Composer, bạn sẽ có thể chạy các lệnh Composer trong thiết bị đầu cuối SSH của mình thông qua `composer COMMAND`. + +:::info Tối ưu hoá + +Sau hầu hết các lệnh, bạn sẽ muốn chạy `composer dump-autoload -a`. Về cơ bản, điều này lưu trữ các tệp PHP để chúng chạy nhanh hơn. + +::: diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..42526a750 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# Tệp cấu hình + +Chỉ có một số nơi không thể cấu hình thông qua bảng điều khiển quản trị Flarum (không bao gồm database), đó chính là tệp `config.php` nằm trong thư mục càid dặt Flarum của bạn. + +Tệp này mặc dù rất nhẹ, nhưng nó chứa các thông tin quan trọng để Flarum của bạn hoạt động. + +Nếu tệp tồn tại, điều đó cho biết rằng Flarum đã được cài đặt. Nó cũng cung cấp cho Flarum với thông tin database và nhiều hơn nữa. + +Dưới đây là tổng quan nhanh về những thứ có trong tệp cấu hình: + +```php + false, // bật tắt chế độ gỡ lỗi, sử dụng để khắc phục sự cố + 'offline' => false, // bật tắt chế độ bảo trì. Quản trị viên và người dùng sẽ không thể truy cập vào trang web. + 'database' => + array ( + 'driver' => 'mysql', // trình điều khiển cơ sở dữ liệu. Vd: MySQL, MariaDB... + 'host' => 'localhost', // máy chủ kết nối, localhost trong hầu hết các trường hợp trừ khi sử dụng dịch vụ bên ngoài + 'database' => 'flarum', // tên cơ sở dữ liệu + 'username' => 'root', // tên người dùng cơ sở dữ liệu + 'password' => '', // mật khẩu cơ sở dữ liệu + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // tiền tố cho các bảng, hữu ích nếu bạn đang chia sẻ cùng một cơ sở dữ liệu với một dịch vụ khác + 'port' => '3306', // cổng kết nối, mặc định là 3306 với MySQL + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // URL trang web, bạn sẽ muốn thay đổi điều này nếu bạn thay đổi tên miền + 'paths' => + array ( + 'api' => 'api', // /api chuyển đến API + 'admin' => 'admin', // /admin chuyển tới quản trị viên + ), +); +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..e1f38674d --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Console + +Ngoài bảng điều khiển quản trị, Flarum cung cấp một số lệnh console để giúp quản lý diễn đàn của bạn qua thiết bị đầu cuối + +Using the console: + +1. `ssh` vào máy chủ nơi lưu trữ cài đặt flarum của bạn +2. `cd` to the folder that contains the file `flarum` +3. Chạy lệnh `php flarum [command]` + +## Lệnh mặc định + +### list + +Liệt kê tất cả các lệnh quản lý có sẵn, cũng như hướng dẫn sử dụng các lệnh quản lý + +### help + +`php flarum help [tên_câu_lệnh]` + +Hiển thị kết quả trợ giúp cho một lệnh nhất định. + +Bạn cũng có thể xuất ra trợ giúp ở các định dạng khác bằng cách sử dụng tùy chọn `--format`: + +`php flarum help --format=xml list` + +Để hiển thị danh sách các lệnh có sẵn, vui lòng sử dụng lệnh danh sách. + +### info + +`php flarum info` + +Get information about Flarum's core and installed extensions. Điều này rất hữu ích cho các sự cố gỡ lỗi và nên được chia sẻ khi yêu cầu hỗ trợ. + +### cache:clear + +`php flarum cache:clear` + +Xóa bộ đệm ẩn phụ trợ, bao gồm js/css đã tạo, bộ đệm định dạng văn bản và các bản dịch đã lưu trong bộ đệm. Thao tác này sẽ được chạy sau khi cài đặt hoặc gỡ bỏ các tiện ích mở rộng và việc chạy này phải là bước đầu tiên khi sự cố xảy ra. + +### assets:publish + +`php flarum assets:publish` + +Xuất bản nội dung từ lõi và tiện ích mở rộng (ví dụ: JS/CSS đã biên dịch, biểu tượng bootstrap, biểu trưng, v.v.). Điều này hữu ích nếu nội dung của bạn bị hỏng hoặc nếu bạn đã chuyển đổi [trình điều khiển hệ thống tệp](extend/filesystem.md) cho đĩa `flarum-asset`. + +### migrate + +`php flarum migrate` + +Chạy tất cả các lần di chuyển chưa thực hiện. Điều này sẽ được sử dụng khi một tiện ích mở rộng sửa đổi cơ sở dữ liệu được thêm vào hoặc cập nhật. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Đặt lại tất cả các lần di chuyển cho một tiện ích mở rộng. Điều này hầu hết được sử dụng bởi các nhà phát triển tiện ích mở rộng, nhưng đôi khi, bạn có thể cần phải chạy điều này nếu bạn đang xóa một tiện ích mở rộng và muốn xóa tất cả dữ liệu của nó khỏi cơ sở dữ liệu. Xin lưu ý rằng tiện ích mở rộng được đề cập hiện phải được cài đặt (nhưng không nhất thiết phải được bật) để tiện ích này hoạt động. + +### schedule:run + +`php flarum schedule:run` + +Nhiều tiện ích mở rộng sử dụng các công việc đã lên lịch để chạy các tác vụ theo chu kỳ. Điều này có thể bao gồm dọn dẹp cơ sở dữ liệu, đăng bản nháp đã lên lịch, tạo sơ đồ trang, v.v. Nếu bất kỳ tiện ích mở rộng nào của bạn sử dụng công việc đã lên lịch, bạn nên thêm một [công việc cron](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) để chạy lệnh này trên một khoảng thời gian đều đặn: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +Nói chung không nên chạy lệnh này theo cách thủ công. + +Lưu ý rằng một số máy chủ không cho phép bạn chỉnh sửa cấu hình cron trực tiếp. Trong trường hợp này, bạn nên tham khảo ý kiến chủ nhà của mình để biết thêm thông tin về cách lên lịch công việc cho cron. + +### schedule:list + +`php flarum schedule:list` + +Lệnh này trả về danh sách các lệnh được lập lịch (xem `schedule:run` để biết thêm thông tin). Điều này hữu ích để xác nhận rằng các lệnh do tiện ích mở rộng của bạn cung cấp đã được đăng ký đúng cách. **Điều này không thể** kiểm tra xem các công việc cron đã được lên lịch thành công hay đang được chạy. \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..3c17433f0 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Tài liệu và Bản dịch + +## Thêm tài liệu + +Thêm tài liệu có thể giúp vô số người dùng Flarum trong tương lai. Một vài ý tưởng về những việc cần làm: + +- Hướng dẫn sử dụng để giúp người dùng Flarum với một số tính năng nâng cao của Flarum. +- [Đặt câu hỏi](faq.md). +- Các bước [khắc phục sự cố](troubleshoot.md) mở rộng. +- Hướng dẫn từng bước để phát triển hoặc cài đặt Flarum. +- [Hướng dẫn tham khảo kỹ thuật](extend/README.md) dành cho lập trình viên tiện ích mở rộng. +- Cải thiện theo nghĩa đen bất kỳ thứ gì khác mà bạn nghĩ chúng tôi nên giải thích kỹ hơn hoặc giải thích rõ hơn. + +Một cách tốt để tìm chủ đề để viết là tìm các câu hỏi phổ biến trong [thẻ hỗ trợ](https://discuss.flarum.org/t/support) của cộng đồng chúng tôi. + +## Dịch Flarum + +Chúng tôi muốn Flarum có thể truy cập được cho tất cả mọi người, bất kể ngôn ngữ! Bằng cách đóng góp các bản dịch, bạn có thể giúp nhiều người khác thưởng thức Flarum. Hơn hết, chúng tôi sử dụng GUI thân thiện với người dùng cho các bản dịch, vì vậy không cần kỹ năng kỹ thuật nào để trợ giúp! + +Bản dịch cho cốt lõi Flarum, tiện ích mở rộng đi kèm và tiện ích mở rộng cộng đồng được quản lý thông qua [Weblate](https://weblate.rob006.net/projects/flarum/). + +Các bản dịch cho tài liệu này được quản lý thông qua [Crowdin](https://crowdin.com/project/flarum-docs). + +Flarum Foundation đã thành lập tổ chức "flarum-lang" để hỗ trợ các biên dịch viên và đảm bảo tính khả dụng liên tục của các gói ngôn ngữ. Bạn có thể tìm hiểu thêm về điều này bằng cách [truy cập kho lưu trữ GitHub](https://github.com/flarum-lang/about). + +Nếu bạn muốn hỗ trợ gói ngôn ngữ hiện có, bắt đầu bản dịch mới hoặc bạn gặp sự cố khi sử dụng weblate hoặc crowdin, tốt nhất hãy [liên hệ với nhóm flarum-lang](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..461308b11 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# Giúp xây dựng Flarum + +Bạn quan tâm đến việc đóng góp vào sự phát triển của Flarum? Thật tuyệt! Từ [mở báo cáo lỗi](bugs.md) đến tạo yêu cầu kéo: mọi yêu cầu đơn lẻ đều được đánh giá cao và hoan nghênh. Flarum sẽ không thể thực hiện được nếu không có sự đóng góp của cộng đồng. + +Trước khi đóng góp, vui lòng đọc [quy tắc ứng xử](code-of-conduct.md). + +Tài liệu này là hướng dẫn cho các nhà phát triển muốn đóng góp mã cho Flarum. Nếu bạn mới bắt đầu, chúng tôi khuyên bạn nên đọc tài liệu [Bắt đầu](/extend/start.md) trong tài liệu Tiện ích mở rộng để hiểu thêm một chút về cách hoạt động của Flarum. + +## Tại sao lại đóng góp Flarum? + +⚡ **Có tác động thực sự.** Có hàng nghìn phiên bản Flarum, với hàng triệu người dùng cuối tổng hợp. Bằng cách đóng góp cho Flarum, mã của bạn sẽ có tác động tích cực đến tất cả chúng. + +🔮 **Định hình tương lai của Flarum.** Chúng tôi có một công việc tồn đọng dài và thời gian có hạn. Nếu bạn sẵn sàng ủng hộ một tính năng hoặc thay đổi, thì điều đó có nhiều khả năng xảy ra hơn và bạn sẽ có thể đưa ra tầm nhìn của mình cho nó. Ngoài ra, lộ trình và các mốc quan trọng của chúng tôi do [nhóm phát triển cốt lõi](https://flarum.org/team) của chúng tôi đặt ra và tất cả chúng tôi đều bắt đầu với tư cách là cộng tác viên. Con đường tốt nhất để tạo ảnh hưởng là đóng góp. + +🧑💻 **Trở thành Kỹ sư giỏi hơn.** Cơ sở mã của chúng tôi hiện đại và chúng tôi đánh giá cao kỹ thuật tốt và mã sạch. Ngoài ra còn có rất nhiều vấn đề thú vị, đầy thách thức cần giải quyết liên quan đến thiết kế, cơ sở hạ tầng, hiệu suất và khả năng mở rộng. Đặc biệt nếu bạn là sinh viên hoặc mới bắt đầu sự nghiệp, làm việc trên Flarum là một cơ hội tuyệt vời để xây dựng các kỹ năng phát triển. + +🎠 **Thật thú vị!** Chúng tôi thực sự thích làm việc trên Flarum: có rất nhiều thử thách thú vị và các tính năng thú vị để xây dựng. Chúng tôi cũng có một cộng đồng tích cực trên [diễn đàn của chúng tôi](https://discuss.flarum.org) và [máy chủ Discord](https://flarum.org/chat). + +## Những gì cần làm + +Hãy xem [Các mốc quan trọng](https://github.com/flarum/core/milestones) sắp tới của chúng tôi để biết tổng quan về những việc cần phải làm. Xem nhãn [Vấn đề đầu tiên tốt nhất](https://github.com/flarum/core/labels/Good%20first%20issue) để biết danh sách các vấn đề tương đối dễ bắt đầu. Nếu có bất cứ điều gì bạn không chắc chắn, đừng ngần ngại hỏi! Tất cả chúng tôi chỉ mới bắt đầu một lần. + +Nếu bạn đang lên kế hoạch tiếp tục làm việc gì đó, vui lòng nhận xét về vấn đề có liên quan hoặc tạo một vấn đề mới trước. Bằng cách này, chúng tôi có thể đảm bảo rằng công việc quý giá của bạn không trở nên vô ích. + +Vì Flarum hướng đến tiện ích mở rộng, chúng tôi thực sự khuyên bạn nên sử dụng [tài liệu về tiện ích mở rộng của chúng tôi](extend/README.md) để làm tài liệu tham khảo khi làm việc trên lõi, cũng như đối với các tiện ích mở rộng đi kèm. Bạn nên bắt đầu với [phần giới thiệu](extend/README.md) để hiểu rõ hơn về triết lý mở rộng của chúng tôi. + +## Thiết lập môi trường + +### Thiết lập Codebase cục bộ + +[flarum/flarum](https://github.com/flarum/flarum) là một ứng dụng "skeleton" sử dụng Composer để tải xuống gói cốt lõi và một loạt các phần mở rộng. Mã nguồn cho Flarum cốt lõi, phần mở rộng và tất cả các gói được sử dụng bởi phần nói trên nằm trong Flarum monorepo [flarum/framework](https://github.com/flarum/framework). Để đóng góp vào những điều này, bạn sẽ cần phải phân nhánh và sao chép cục bộ kho lưu trữ monorepo, sau đó thêm nó vào môi trường phát triển của bạn dưới dạng [đường dẫn kho lưu trữ Composer](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com/Hello!
+ } +} +``` + +### Đặt Trang làm Trang chủ + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Tiêu đề trang + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..7146b83c1 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,422 @@ +# Phát triển Frontend + +This page describes how to make changes to Flarum's user interface. How to add buttons, marquees, and blinking text. 🤩 + +[Remember](/extend/start.md#architecture), Flarum's frontend is a **single-page JavaScript application**. There's no Twig, Blade, or any other kind of PHP template to speak of. The few templates that are present in the backend are only used to render search-engine-optimized content. All changes to the UI need to be made via JavaScript. + +Flarum has two separate frontend applications: + +* `forum`, the public side of your forum where users create discussions and posts. +* `admin`, the private side of your forum where, as an administrator of your forum, you configure your Flarum installation. + +They share the same foundational code, so once you know how to extend one, you know how to extend both. + +:::tip Typings! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Biên dịch và cấu trúc tập tin + +This portion of the guide will explain the necessary file setup for extensions. Once again, we highly recommend using the [Flarum CLI](https://github.com/flarum/cli) to set up the file structure for you. That being said, you should still read this to understand what's going on beneath the surface. + +Before we can write any JavaScript, we need to set up a **transpiler**. This allows us to use [TypeScript](https://www.typescriptlang.org/) and its magic in Flarum core and extensions. + +In order to do this transpilation, you need to be working in a capable environment. No, not the home/office kind of environment – you can work in the bathroom for all I care! I'm talking about the tools that are installed on your system. You'll need: + +* Node.js and npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +This can be tricky because everyone's system is different. From the OS you're using, to the program versions you have installed, to the user access permissions – I get chills just thinking about it! If you run into trouble, ~~tell him I said hi~~ use [Google](https://google.com) to see if someone has encountered the same error as you and found a solution. If not, ask for help from the [Flarum Community](https://discuss.flarum.org) or on the [Discord chat](https://flarum.org/discord/). + +It's time to set up our little JavaScript transpilation project. Create a new folder in your extension called `js`, then pop in a couple of new files. A typical extension will have the following frontend structure: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +This is a standard JS [package-description file](https://docs.npmjs.com/files/package.json), used by npm and Yarn (Javascript package managers). You can use it to add commands, js dependencies, and package metadata. We're not actually publishing a npm package: this is simply used to collect dependencies. + +Please note that we do not need to include `flarum/core` or any flarum extensions as dependencies: they will be automatically packaged when Flarum compiles the frontends for all extensions. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) is the system that actually compiles and bundles all the javascript (and its dependencies) for our extension. To work properly, our extensions should use the [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (shown in the above example). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js và forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Nhập + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Biên dịch + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Đăng ký asset + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..e22b5f116 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Tìm kiếm và Lọc + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..07e3e4d91 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Service Provider + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. [Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. The most common use case for service providers is to create, modify, or replace container bindings. That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..ffefdcde5 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Settings + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..88fa6ed95 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Bắt đầu + +Want to build a Flarum extension? You've come to the right place! This document will take you through some essential concepts, after which you'll build your first Flarum extension from scratch. + +## Cấu tạo + +Để hiểu cách mở rộng Flarum, trước tiên chúng ta cần hiểu một chút về cách Flarum được xây dựng. + +Be aware that Flarum uses some _modern_ languages and tools. If you've only ever built WordPress plugins before, you might feel a bit out of your depth! That's OK — this is a great time to learn cool new things and extend your skillset. However, we would advise that you become somewhat familiar with the technologies described below before proceeding. + +Flarum được tạo thành từ ba lớp: + +* First, there is the **backend**. This is written in [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), and makes use of a wide array of [Laravel](https://laravel.com/) components and other packages via [Composer](https://getcomposer.org/). You'll also want to familiarize yourself with the concept of [Dependency Injection](https://laravel.com/docs/8.x/container), which is used throughout our backend. + +* Second, the backend exposes a **public API** which allows frontend clients to interface with your forum's data. This is built according to the [JSON:API specification](https://jsonapi.org/). + +* Finally, there is the default web interface which we call the **frontend**. This is a [single-page application](https://en.wikipedia.org/wiki/Single-page_application) which consumes the API. It's built with a simple React-like framework called [Mithril.js](https://mithril.js.org). + +Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the **backend**, expose that data in the **public API**, and then display it and allow users to edit it on the **frontend**. + +So... how do we extend these layers? + +## Bộ mở rộng + +In order to extend Flarum, we will be using a concept called **extenders**. Extenders are *declarative* objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created). + +Every extender is different. However, they will always look somewhat similar to this: + +```php +// Đăng ký JavaScript và tệp CSS để được gửi bằng frontend của diễn đàn +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls. + +To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). _Everything_ you do in your extension should be done via extenders, because they are a **guarantee** we are giving to you that a future minor release of Flarum won't break your extension. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hello World + +Want to see an extender in action? The `extend.php` file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Now pay your forum a visit for a pleasant (albeit extremely obtrusive) greeting. 👋 + +For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the `extend.php` file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension! + +## Gói Tiện ích mở rộng + +[Composer](https://getcomposer.org) is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly. + +As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice! + +During development, you can work on your extensions locally and set up a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path) to install your local copy. Create a new `packages` folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here: + +```bash +composer config repositories.0 path "packages/*" +``` + +Now let's start building our first extension. Make a new folder inside `packages` for your extension called `hello-world`. We'll put two files in it: `extend.php` and `composer.json`. These files serve as the heart and soul of the extension. + +### extend.php + +The `extend.php` file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the `Frontend` extender that you had earlier. + +### composer.json + +Chúng tôi cần cho Composer biết một chút về gói của chúng tôi và chúng tôi có thể làm điều này bằng cách tạo tệp `composer.json`: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": "^1.0.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** là tên của gói Composer ở định dạng `vendor/package`. + * You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using `acme` as your vendor name. + * Bạn nên đặt tiền tố phần `package` bằng `flarum-`để cho biết rằng đó là một gói được thiết kế đặc biệt để sử dụng với Flarum. + +* **description** là một mô tả ngắn một câu về chức năng của tiện ích. + +* **type** MUST be set to `flarum-extension`. This ensures that when someone "requires" your extension, it will be identified as such. + +* **require** chứa danh sách các phần phụ thuộc của tiện ích mở rộng của bạn. + * Bạn sẽ muốn chỉ định phiên bản Flarum mà tiện ích mở rộng của bạn tương thích tại đây. + * Đây cũng là nơi liệt kê các thư viện Composer khác mà mã của bạn cần để hoạt động. + +* **autoload** tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase. + +* **extra.flarum-extension** chứa một số thông tin cụ thể về Flarum, như tên hiển thị của tiện ích mở rộng của bạn và biểu tượng của nó trông như thế nào. + * **title** là tên hiển thị của tiện ích mở rộng của bạn. + * **icon** is an object which defines your extension's icon. The **name** property is a [Font Awesome icon class name](https://fontawesome.com/icons). All other properties are used as the `style` attribute for your extension's icon. + +Xem tài liệu [lược đồ composer.json](https://getcomposer.org/doc/04-schema.md) để biết thông tin về các thuộc tính khác mà bạn có thể thêm vào `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Sử dụng CLI để tự động tạo giàn giáo cho tiện ích mở rộng của bạn: +```bash +$ flarum-cli init +``` + +::: + +### Cài đặt Tiện ích mở rộng của bạn + +The final thing we need to do to get up and running is to install your extension. Navigate to the root directory of your Flarum install and run the following command: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Sau khi hoàn tất, hãy tiếp tục và kích hoạt trên trang Quản trị của diễn đàn, sau đó điều hướng trở lại diễn đàn của bạn. + +*tiếng vù vù, vù vù, tiếng kêu kim loại* + +Woop! Hello to you too, extension! + +We're making good progress. We've learned how to set up our extension and use extenders, which opens up a lot of doors. Read on to learn how to extend Flarum's frontend. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..f9d866094 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Testing + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + +something
Hello World!
; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return{this.counter}
; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +{this.attrs.counter}
; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +Counter: {app.counter.getCount()}
+Hello World!{this.showContent ? ' Extra Content!' : ''}
+Hello World!
Hello World
" + } + }, + // [...] còn nhiều cuộc thảo luận khác + ] +} +``` + +### Tạo cuộc thảo luận + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +Phản hồi trả về bao gồm ID của cuộc thảo luận mới: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] các quan hệ khác + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] các thuộc tính khác + } + } + // [...] other includes + ] +} +``` + +### Tạo người dùng + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Lỗi + +Flarum sử dụng nhiều mã trạng thái HTTP khác nhau và bao gồm các mô tả lỗi tuân theo [JSON:Thông số lỗi API](https://jsonapi.org/format/#errors). + +Dưới đây là một số lỗi phổ biến mà bạn có thể gặp phải khi sử dụng REST API: + +### Mã token CSRF không khớp + +Nếu bạn nhận được lỗi HTTP 400 với thông báo `csrf_token_mismatch`, điều đó có nghĩa là header `Authorization` không có hoặc không hợp lệ và Flarum đã cố gắng xác thực thông qua cookie phiên. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Lỗi xác thực + +Lỗi xác thực được trả về với mã trạng thái 422 HTTP. Tên của trường không hợp lệ được trả về dưới dạng giá trị `pointer`. Có thể có nhiều lỗi cho một trường cùng một lúc. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..66b38413b --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Chủ đề + +Mặc dù chúng tôi đã làm việc chăm chỉ để làm cho Flarum đẹp nhất có thể, nhưng mỗi cộng đồng có thể sẽ muốn thực hiện một số chỉnh sửa/sửa đổi để phù hợp với phong cách mong muốn của họ. + +## Bảng điều khiển Quản trị + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Tại đây, bạn có thể: + +- Chọn màu chủ đề +- Chuyển đổi chế độ tối và màu đầu trang +- Tải lên icon và favicon (icon hiển thị trong các tab của trình duyệt) +- Thêm HTML cho đầu trang và chân trang tùy chỉnh +- Thên [mã LESS/CSS](#css-theming) để thay đổi cách các phần tử được hiển thị + +## Chủ đề CSS + +CSS là một ngôn ngữ biểu định kiểu cho các trình duyệt biết cách hiển thị các phần tử của một trang web. Nó cho phép chúng tôi sửa đổi mọi thứ từ màu sắc, phông chữ đến kích thước phần tử và vị trí cho đến hình ảnh động. Thêm CSS tùy chỉnh có thể là một cách tuyệt vời để sửa đổi cài đặt Flarum của bạn cho phù hợp với chủ đề. + +Hướng dẫn CSS nằm ngoài phạm vi của tài liệu này, nhưng có rất nhiều tài nguyên trực tuyến tuyệt vời để tìm hiểu kiến thức cơ bản về CSS. + +:::tip + +Flarum thực sự sử dụng LESS, giúp viết CSS dễ dàng hơn bằng cách cho phép các biến, điều kiện và hàm. + +::: + +## Tiện ích mở rộng + +[Hệ thống tiện ích mở rộng](extensions.md) linh hoạt của Flarum cho phép bạn thêm, xóa hoặc sửa đổi trên thực tế bất kỳ phần nào của Flarum. Nếu bạn muốn thực hiện các sửa đổi đáng kể về chủ đề ngoài việc thay đổi màu sắc/kích thước/kiểu dáng, thì một tiện ích mở rộng tùy chỉnh chắc chắn là cách tốt nhất. Để tìm hiểu cách tạo tiện ích mở rộng, hãy xem [tài liệu về tiện ích mở rộng](extend/README.md) của chúng tôi! diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..4014c6d98 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Khắc phục sự cố + +Nếu Flarum không cài đặt hoặc hoạt động như mong đợi, điều đầu tiên bạn nên làm là *kiểm tra lại* xem môi trường của bạn có đáp ứng [yêu cầu hệ thống](install.md#server-requirements). Nếu bạn đang thiếu thứ gì đó mà Flarum cần để chạy, trước tiên bạn cần phải khắc phục điều đó. + +Tiếp theo, bạn nên dành vài phút để tìm kiếm trong [Diễn đàn hỗ trợ](https://discuss.flarum.org/t/support) và [trình theo dõi vấn đề](https://github.com/flarum/core/issues). Có thể ai đó đã báo cáo sự cố và bản sửa lỗi đã có sẵn hoặc đang được xử lý. Nếu bạn đã tìm kiếm kỹ lưỡng và không thể tìm thấy bất kỳ thông tin nào về vấn đề, đã đến lúc bắt đầu khắc phục sự cố. + +## Step 0: Activate debug mode + +:::danger Bỏ qua phần Sản xuất + +Các công cụ gỡ lỗi này rất hữu ích, nhưng có thể tiết lộ thông tin không nên công khai. Đây là những bước tốt nếu bạn đang sử dụng môi trường dàn dựng hoặc phát triển, nhưng nếu bạn không biết mình đang làm gì, hãy bỏ qua bước này khi ở trong môi trường sản xuất. + +::: + +Trước khi tiếp tục, bạn nên kích hoạt các công cụ gỡ lỗi của Flarum. Chỉ cần mở **config.php** bằng trình soạn thảo văn bản, thay đổi giá trị `debug` thành `true =` và lưu tệp. Điều này sẽ khiến Flarum hiển thị các thông báo lỗi chi tiết, giúp bạn có cái nhìn sâu sắc về những gì đang xảy ra. + +Nếu bạn thấy các trang trống và thay đổi ở trên không hữu ích, hãy thử đặt `display_errors` thành `On` trong tệp cấu hình **php.ini** của bạn. + +## Bước 1: Các lỗi phổ biến + +Rất nhiều vấn đề có thể được khắc phục bằng cách sau: + +* Xóa bộ nhớ cache của trình duyệt của bạn +* Xóa bộ đệm backend bằng [`php flarum cache:clear`](console.md). +* Đảm bảo rằng cơ sở dữ liệu của bạn được cập nhật với [`php flarum migrate`](console.md). +* Đảm bảo rằng [cấu hình email](mail.md) trong bảng điều khiển quản trị của bạn là đúng: cấu hình email không hợp lệ sẽ gây ra lỗi khi đăng ký, đặt lại mật khẩu, thay đổi email và gửi thông báo. +* Kiểm tra xem `config.php` của bạn có đúng không. Ví dụ: đảm bảo rằng `url` đang được sử dụng (`https` so với `http` và vấn đề phân biệt chữ hoa chữ thường ở đây!). +* Một thủ phạm tiềm năng có thể là đầu trang tùy chỉnh, chân trang tùy chỉnh hoặc LESS tùy chỉnh. Nếu sự cố của bạn nằm ở giao diện người dùng, hãy thử tạm thời xóa chúng qua trang Giao diện của trang tổng quan quản trị. + +Bạn cũng sẽ muốn xem kết quả đầu ra của [`php flarum info`](console.md) để đảm bảo rằng không có điều gì chính xảy ra. + +## Bước 2: Tạo lại vấn đề + +Cố gắng làm cho vấn đề xảy ra một lần nữa. Hãy chú ý cẩn thận đến những gì bạn đang làm khi nó xảy ra. Nó xảy ra mọi lúc, hay chỉ thỉnh thoảng? Hãy thử thay đổi một cài đặt mà bạn cho rằng có thể ảnh hưởng đến sự cố hoặc thứ tự mà bạn đang thực hiện. Nó có xảy ra trong một số điều kiện, nhưng không phải những điều kiện khác? + +Nếu gần đây bạn đã thêm hoặc cập nhật tiện ích mở rộng, bạn nên tạm thời vô hiệu hóa tiện ích đó để xem liệu điều đó có làm cho sự cố biến mất hay không. Đảm bảo rằng tất cả các tiện ích mở rộng của bạn đều được sử dụng với phiên bản Flarum bạn đang chạy. Các tiện ích mở rộng lỗi thời có thể gây ra nhiều vấn đề. + +Ở một nơi nào đó trong quá trình thực hiện, bạn có thể nhận ra ý tưởng về nguyên nhân gây ra sự cố của mình và tìm ra cách khắc phục nó. Nhưng ngay cả khi điều đó không xảy ra, bạn có thể sẽ tìm thấy một vài manh mối có giá trị giúp chúng tôi tìm ra điều gì đang xảy ra sau khi bạn đã gửi báo cáo lỗi của mình. + +## Bước 3: Thu thập thông tin + +Nếu có vẻ như bạn đang cần trợ giúp để giải quyết vấn đề, thì đã đến lúc nghiêm túc với việc thu thập dữ liệu. Tìm thông báo lỗi hoặc thông tin khác về sự cố ở những nơi sau: + +* Hiển thị trên trang thực tế +* Được hiển thị trong console của trình duyệt (Chrome: More tools -> Developer Tools -> Console) +* Được ghi lại trong nhật ký lỗi của máy chủ (ví dụ: `/var/log/nginx/error.log`) +* Được ghi lại trong nhật ký lỗi của PHP-FPM (ví dụ: `/var/log/php7.x-fpm.log`) +* Được ghi lại bởi Flarum (`storage/logs`) + +Sao chép bất kỳ tin nhắn nào vào tệp văn bản và ghi lại một vài ghi chú về *khi* xảy ra lỗi, bạn *bị gì* đang làm vào thời điểm đó. Đảm bảo bao gồm bất kỳ thông tin chi tiết nào bạn có thể thu thập được về các điều kiện mà sự cố xảy ra và không xảy ra. Thêm càng nhiều thông tin càng tốt về môi trường máy chủ của bạn: phiên bản hệ điều hành, phiên bản máy chủ web, phiên bản PHP và trình xử lý. + +## Bước 4: Chuẩn bị một báo cáo + +Khi bạn đã thu thập tất cả thông tin có thể về sự cố, bạn đã sẵn sàng để gửi báo cáo lỗi. Vui lòng làm theo hướng dẫn về [Báo cáo lỗi](bugs.md). + +Nếu bạn phát hiện ra điều gì đó mới về vấn đề này sau khi gửi báo cáo, vui lòng thêm thông tin đó vào cuối bài đăng ban đầu của bạn. Bạn nên gửi báo cáo ngay cả khi bạn đã tự mình giải quyết vấn đề, vì những người dùng khác cũng có thể được hưởng lợi từ giải pháp của bạn. Nếu bạn đã tìm thấy giải pháp tạm thời cho vấn đề, hãy nhớ đề cập đến vấn đề đó. \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..9de400ff6 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Cập nhật + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +Để cập nhật Flarum, bạn cần sử dụng [Composer](https://getcomposer.org). Nếu bạn không biết gì về nó, bạn cần phải biết 1 ít về Composer để cài đặt Flarum, đọc [hướng dẫn](composer.md) để biết cách cài đặt và sử dụng như thế nào. + +Nếu cập nhật trên các phiên bản chính (ví dụ: <= 0.1.0 đến 1.x.x, 1.x.x thành 2.x.x, ...), hãy nhớ đọc "hướng dẫn cập nhật phiên bản chính" thích hợp trước khi chạy các bước nâng cấp chung. + +## Các bước chung + +**Bước 1:** Đảm bảo các tiện ích mở rộng của bạn có phiên bản tương thích với phiên bản Flarum bạn đang cài đặt. Điều này chỉ cần thiết trên các phiên bản chính (ví dụ: bạn có thể không cần kiểm tra điều này nếu nâng cấp từ v1.0.0 lên v1.1.0, giả sử các tiện ích mở rộng của bạn tuân theo cách lập phiên bản được đề xuất). Bạn có thể kiểm tra điều này bằng cách xem [Cuộc thảo luận](https://discuss.flarum.org/t/extensions) của tiện ích mở rộng, tìm kiếm nó trên [Packagist](http://packagist.org/) hoặc kiểm tra cơ sở dữ liệu như [Extiverse](https://extiverse.com). Bạn sẽ cần phải xóa (không chỉ tắt) bất kỳ tiện ích mở rộng nào không tương thích trước khi cập nhật. Hãy kiên nhẫn với các nhà phát triển tiện ích mở rộng! + +**Bước 2:** Hãy xem tệp `composer.json` của bạn. Trừ khi bạn có lý do để yêu cầu các phiên bản tiện ích mở rộng hoặc thư viện cụ thể, bạn nên đặt chuỗi phiên bản của mọi thứ ngoại trừ `flarum/core ` thành `*` (bao gồm cả `flarum/tags`, `flarum/mentions` và các tiện ích mở rộng đi kèm khác). Đảm bảo rằng `flarum/core` KHÔNG được đặt thành `*`. Nếu bạn đang muốn cài phiên bản cụ thể của Flarum, hãy đặt `flarum/core` thành phiên bản đó (ví dụ: `"flarum/core":"v0.1.0-beta.16"`). Nếu bạn muốn phiên bản mới nhất, hãy sử dụng `"flarum/core":"^1.0"`. + +**Bước 3:** Nếu cài đặt cục bộ của bạn sử dụng [bộ mở rộng cục bộ](extenders.md), đảm bảo rằng chúng được cập nhật với những thay đổi trong Flarum. + +**Bước 4:** Chúng tôi khuyên bạn nên tắt tiện ích của bên thứ ba trong trang tổng quan quản trị trước khi cập nhật. Bước này không bắt buộc, nhưng sẽ giúp gỡ lỗi dễ dàng hơn nếu bạn gặp sự cố. + +**Bước 5:** Đảm bảo rằng phiên bản PHP của bạn được hỗ trợ bởi phiên bản Flarum mà bạn đang chuẩn bị nâgn cấp, và kiểm tra nó bằng cách sử dụng Composer 2 (`composer --version)`. + +**Bước 6:** Cuối cùng, chạy lệnh sau để cập nhật: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Bước 7:** Nếu có thể, hãy khởi động lại máy chủ PHP và opcache của bạn. + +## Hướng dẫn cập nhật phiên bản chính + +### Cập nhật từ Beta (<=0.1.0) lên Ổn định v1 (^1.0.0) + +1. Thực hiện các bước 1-5 ở trên. +2. Thay đổi chuỗi phiên bản của tất cả các tiện ích mở rộng đi kèm (`flarum/tags`, `flarum/mentions`, `flarum/likes`, vv) trong `composer.json` từ `^0.1.0` thành `*`. +3. Đổi phiên bản của `flarum/core` trong `composer.json` từ `^0.1.0` thành `^1.0`. +4. Xoá dòng `"minimum-stability": "beta",` từ tệp `composer.json` +5. Thực hiện bước 6 và 7 ở trên. + +## Các vấn đề gặp phải + +Có 2 nơi chính mà bạn có thể gặp lỗi khi cập nhật Flarum: khi đang chạy chính lệnh cập nhật hoặc khi truy cập diễn đàn sau khi cập nhật. + +### Gặp lỗi khi cập nhật + +Sau đây, chúng ta sẽ xem xét một số loại sự cố thường gặp khi cố gắng cập nhật Flarum. + +--- + +Nếu đầu ra ngắn và chứa: + +``` +Nothing to modify in lock file +``` + +Hoặc không liệt kê `flarum/core` như một gói cập nhật và bạn không sử dụng phiên bản flarum mới nhất: + +- Xem lại bước 2 ở trên, đảm bảo rằng tất cả các tiện ích mở rộng của bên thứ ba đều có dấu hoa thị cho chuỗi phiên bản của chúng. +- Đảm bảo yêu cầu phiên bản `flarum/core` của bạn không bị khóa đối với một phiên bản nhỏ cụ thể (ví dụ: `v0.1.0-beta.16` bị khóa, `^1.0.0` không). Nếu bạn đang cố gắng cập nhật các phiên bản chính của Flarum, hãy làm theo hướng dẫn cập nhật phiên bản chính có liên quan ở trên. + +--- + +Cho các lỗi khác, thử chạy `composer why-not flarum/core PHIÊN_BẢN_BẠN_MUỐN_NÂNG_CẤP_LÊN` + +Nếu đầu ra giống kiểu như này: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +Rất có thể một số tiện ích mở rộng của bạn chưa được cập nhật lên phiên bản mới nhất. + +- Xem lại bước 1, đảm bảo rằng phiên bản của các tiện ích mở rộng của bạn tương thích với phiên bản core mà bạn đang cần cập nhật. Hãy xoá bất kỳ tiện ích nào không tương thích. +- Đảm bảo rằng bạn đang chạy `composer update` với tất cả các flag được chỉ định trong bước cập nhật. + +Nếu các cách khắc phục trên không giúp ích được cho bạn, hãy tham gia [Hỗ trợ diễn đàn](https://discuss.flarum.org/t/support). Khi đăng bài hỏi cách khắc phục, hãy kèm theo nội dung khi chạy lệnh `php flarum info` và `composer why-not flarum/core PHIÊN_BẢN_MÀ_BẠN_MUỐN_NÂNG_CẤP_LÊN`. + +### Gặp lỗi sau khi cập nhật + +Nếu bạn không thể truy cập diễn đàn của bạn sau khi cập nhật, làm theo [hướng dẫn khắc phục sự cố](troubleshoot.md). diff --git a/i18n/zh/docusaurus-plugin-content-docs/current.json b/i18n/zh/docusaurus-plugin-content-docs/current.json index f4ec6a00a..1e5f99cf2 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current.json +++ b/i18n/zh/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "下一节", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "内部文档", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/README.md b/i18n/zh/docusaurus-plugin-content-docs/current/README.md index 0c5c7d96d..b98c1530a 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/README.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/README.md @@ -16,7 +16,7 @@ Flarum 的前身是 [esoTalk](https://github.com/esotalk/esoTalk) 和 [FluxBB](h * **漂亮、响应式。 ** 以人为本的论坛软件。 Flarum 被精心设计以在不同平台间保持一致性和直观性,开箱即用。 -* **强大、可扩展。** 您可以客制化、扩展或集成 Flarum 以满足您的社区需求。 Flarum 基于 [MIT 协议](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 +* **强大、可扩展。** 您可以客制化、扩展或集成 Flarum 以满足您的社区需求。 Flarum 基于 [MIT 协议](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 * **免费、开源。 ** Flarum 以 [MIT 许可证](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md b/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md index 857eb2513..3b174f36b 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md @@ -22,7 +22,7 @@ ### 提高自己的曝光度 -想发起一个新讨论? 请务必先阅读我们的 [常见问题](faq.md),通过其中的相关链接充分了解这个项目。 然后花一些时间浏览论坛,熟悉一下 [标签系统](https://discuss.flarum.org/tags),并搜索一些关键词,*可能您想讨论的早已被大家讨论过。 +想发起一个新讨论? 请务必先阅读我们的 [常见问题](faq.md),通过其中的相关链接充分了解这个项目。 然后花一些时间浏览论坛,熟悉一下 [标签系统](https://discuss.flarum.org/tags),并搜索一些关键词,*可能您想讨论的早已被大家讨论过。 当您确定要发起一个讨论时,请牢记: diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..b98c1530a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# 关于 Flarum + +Flarum 是一款非常简洁的开源论坛软件。 它响应快速、简便易用,拥有打造一片成功的社区所需的所有功能。 它也极其可扩展,允许达到终极的可定制性。 + + + +## 目标 + +Flarum 的前身是 [esoTalk](https://github.com/esotalk/esoTalk) 和 [FluxBB](https://fluxbb.org), 它生来就被设计如此: + +* **快速、简单。 ** 不杂乱不臃肿,没有复杂的依赖关系。 Flarum 使用 PHP 构建,因此很容易被部署。 界面采用高性能且小巧的 JavaScript 框架 [Mithril](https://mithril.js.org)。 + +* **漂亮、响应式。 ** 以人为本的论坛软件。 Flarum 被精心设计以在不同平台间保持一致性和直观性,开箱即用。 + +* **强大、可扩展。** 您可以客制化、扩展或集成 Flarum 以满足您的社区需求。 Flarum 基于 [MIT 协议](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 + +* **免费、开源。 ** Flarum 以 [MIT 许可证](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 + +你可以在这里阅读更多关于我们 [对于 Flarum 的哲学和价值观](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values) 的信息。 + +## 帮助Flarum项目 + +Flarum 是 [免费、开源](https://github.com/flarum/core) 的软件,由志愿者们维护和管理。 我们依靠社区的贡献来帮助我们改进和拓展 Flarum。 + +🧑💻 如果你是一个开发者,可以考虑 [为Flarum或者其扩展做出贡献](contributing.md)。 这是帮助 Flarum 的**最有效的方式**,而且您的帮助可能会产生很大的影响:市面上有成千上万的Flarum站点,拥有数百万的最终用户。 + +🧩 如果有您缺少的功能,或您有一些新的想法,[编写一个自定义扩展](extend/README.md) 将使 Flarum 更适合您和其他人使用。 + +✒️ 如果您在技术写作方面有经验,那么您对[我们文档](https://github.com/flarum/docs/issues)的贡献将有助于未来的用户、管理员和开发人员充分利用 Flarum。 + +🌐 如果您会说多种语言,那么您可以 [为Flarum提供翻译](extend/language-packs.md),从而帮助世界各地无数用户访问 Flarum。 + +💸 Flarum基金会 并不通过Flarum赚钱,但确实有账单要付。 首先,非常感谢您有捐款意向,您可以在 [Github Sponsors](https://github.com/sponsors/flarum) 或 [OpenCollective](https://opencollective.com/flarum) 上捐款。 在过去,我们还能够在财务上支持一些核心开发人员,这样他们就可以兼职工作于 Flarum。 如果没有您的财政支持,这是不可能的。 + +🧑🤝🧑 加入 [我们的社区](https://discuss.flarum.org) 来讨论 Flarum 的发展,获得实例帮助,或者遇见一些很酷的人! 如果您熟悉 Flarum,您还可以帮助初学者! + +🐛 如果有 bug 困扰着您,或者您脑海中有一个功能的想法,在您告诉我们之前我们是不会知道的! 我们通过 [GitHub issues](https://github.com/flarum/core/issues) 跟踪错误、建议和未来的开发计划。 如果已经有 issue 被打开,点个赞和添加一些(建设性的)额外信息可能对我们非常有帮助! + +📣 如果您喜欢 Flarum ,请考虑在博客/推特/聊天中提到它! 更多的人认识到 Flarum,就会有更多的人参与 Flarum,从而带来更多的活动、更好的扩展和更快的发展。 + +没有我们社区的贡献,Flarum就不会有今天。 如果您有意贡献,请参阅我们的 [开发人员贡献](contributing.md) 和 [其他贡献](contributing-docs-translations.md) 文档以获取更多信息。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..74a41cdbc --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# 后台管理面板 + +Flarum 管理面板是一个友好的论坛管理界面。 且只对「管理组」成员可见。 点击论坛右上角您的 **用户名**, 选择 **后台管理** 即可进入管理面板。 + +管理员控制面板有如下部分,具体是: +- **仪表盘** - 显示主要的管理员控制面板,包含统计信息和其他相关信息。 +- [常规](https://docs.flarum.org/mail) - 设置论坛名称、简介以及其他基础设置。 +- **邮箱** - 允许您配置论坛邮件服务。 更多信息请 [点击此处](https://docs.flarum.org/mail)。 +- **权限** - 显示每个用户组的权限,并允许您配置全站和特定范围。 +- **外观** - 允许您自定义论坛的颜色、图标和添加额外的 CSS 以自定义论坛样式。 +- **用户** - 为您提供论坛中所有用户的分页列表,可以在此编辑或管理用户。 + +除了以上提到的这些部分,主管理面板还通过_扩展_部分来允许你管理安装的扩展,这也包括 Flarum 的核心扩展,例如 Tags。 在 _主题 _ 和 _语言_ 模块下,您可以修改论坛主题或使用扩展以适应多语言。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/appearance.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/appearance.md new file mode 100644 index 000000000..6b4c5452f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/appearance.md @@ -0,0 +1,3 @@ +# 外观 +此页面正在建设中。 +This page is under construction. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..49366fae4 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# 反馈 Bug + +:::danger 安全漏洞 + +如果您发现 Flarum 存在安全漏洞,请遵循我们的[安全政策](https://github.com/flarum/core/security/policy),我们会及时处理 + +::: + +感谢您帮助我们测试 Flarum! 我们很高兴让您加入这个队伍! 我们需要可以*排除问题*和*清晰地沟通*的人。 您可能知道,优秀的错误报告需要花费一些时间和精力。 如果您可以做到这些,那让我们开始吧! + +## 重复项 + +已经发现了 Bug? 太棒了! 我们很乐意听到关于它的消息— 但首先您应该检查一下相关情况,以确保您不会在一个已知问题上浪费时间: + +- 搜索我们的 [支持论坛](https://discuss.flarum.org/t/support) 来查看它是否已经报告。 +- 我们也可能正在进行修复,所以也请搜索我们的 [问题跟踪器](https://github.com/flarum/core/issues)。 + +在 *彻底地*搜索一番后,如果无人报告该问题,欢迎您提交报告。 如果只是一个简单的小问题(例如单词拼写问题或图像问题),请直接跳到下一节。 但如果您看到错误,或者它已经明显损坏,我们需要您先收集一些信息。 请跳转到我们的 [故障排除](troubleshoot.md) 指南并遵循那里的指引。 请收集尽可能多的信息! + +## 报告 + +我们在GitHub上跟踪问题。 请您确保在 [正确的仓库](https://github.com/flarum) 创建问题(Issue),并填写模版中的所有内容。 + +如果可以,请检查最新版本的 Flarum 是否可以重现该问题。 如果您使用的是预发布版本或开发版本,请指出您正在使用的版本。 + +记住:错误报告的目的是让我们轻松地重现并修复它。 您可能需要阅读 [这篇文章](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html),了解如何撰写有效的错误报告。 请您 **务必** 清晰描述重现问题的必要步骤。 没有明确重现步骤的问题将不会被标记/分类。 如果一个标记为「需要验证(needs verification)」的问题从被标记开始 5 天内创建者没有进一步反馈信息,该问题将被关闭。 + +一旦您提交了报告,请您 *持续关注* 并耐心等待。 我们可能需要要求进一步的细节或说明。 但我们总是有很多事情要做,所以我们可能需要一段时间才会处理您的报告。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..3b174f36b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# 行为准则 + +### _欢迎光临 Flarum 社区!_ + +... 感谢您的加入! 我们对 Flarum 充满信心与激情,也很高兴认识同样的人。 我们希望 *每个人* 都能从 Flarum 及其社区中得到最大的帮助,因此请阅读并遵守下列准则。 我们希望每位用户都能充分利用 Flarum 和 Flarum 社区,因此,请您阅读并遵守以下准则。 无论您是使用我们的论坛,还是在 Discord、GitHub 上交流,亦或是在其他平台进行任何形式的交流,这些准则均适用。 + +### 重中之重,为人友善! + +我们在这里探讨与 Flarum 有关的事情,并努力使她成长为一个更完美的程序。 批判思维(当然,得通过合理的论证)是其中重要的一环。 不过千万不要冲动,不要让事态演变成人身攻击,不要让消极情绪搞人心态。 因此,请杜绝以下行为: + +- 发表攻击性或辱骂性的、以及任何形式的仇恨词汇或言论; +- 发表旨在骚扰、冒充或诽谤他人的帖子; +- 毫无必要地删除已发布的帖子; +- 未经自然人同意,滥用或企图滥用、公开或企图公开他人的个人信息; +- 发表淫秽或色情内容(包括但不限于文字、链接或图片等); +- 发表垃圾信息、钓鱼贴,以及任何旨在破坏本网站的行为; +- 讨论盗版软件或类似事情。 + +*上述条例将作为版主采取行动的依据。 * 如果您对其他成员有意见,请不要相互对峙。 如果违规行为发生于论坛,请 *举报* 相关帖字,然后等待工作人员处理。 否则,请通过我们的 [联系页面](https://flarum.org/foundation/contact) 报告不合法的违规行为。 + +我们的管理员和版主可以编辑或删除任何具有冒犯性或破坏性的内容。 严重或屡次违规的用户,可能会被封禁账户。 所以,你懂的,*待人友善一些*。 😎 + +### 提高自己的曝光度 + +想发起一个新讨论? 请务必先阅读我们的 [常见问题](faq.md),通过其中的相关链接充分了解这个项目。 然后花一些时间浏览论坛,熟悉一下 [标签系统](https://discuss.flarum.org/tags),并搜索一些关键词,*可能您想讨论的早已被大家讨论过。 + +当您确定要发起一个讨论时,请牢记: + +- 起个好标题! 如果您的标题能简洁明了地阐明您要讨论的内容,您会得到更加理想的结果。 +- 标签要选对! 这将增加帖子被及时阅读、回复的可能性。 +- *不要*翻来覆去的发布相同主题的帖子。这样通常会适得其反。 +- 如果不使用标签组标记为多语言,则请*务必使用英语来发表帖子*。如果我们无法理解你发的帖子想表达什么,我们就无从帮助你。 +- 不要在帖子中签名或者添加小尾巴! 个人资料的辨识度足够了。 + +帮我们一起把事务整理的有条不紊吧。 可别让我们把用来了解您、帮助您解决问题、谈论 Flarum 的大好时光浪费在杂七杂八的琐碎事儿上,您说对吗? 毕竟,那才是我们应该在这里做的事情。 + +### 提升您回帖的价值 + +大家参与讨论,都是希望自己的观点或建议能被他人采纳、为他人提供帮助。 既然如此,为什么不从一开始就让您的回帖值得一读呢? + +- 不要回复标题。 花点时间 *看一下* 看看一楼在说什么,至少先 *速览一下* 后面的对话。 +- 问问自己,您的回复是否对讨论有帮助。 如果没有,请斟酌斟酌。 +- 避免仅仅为了同意某人就去顶帖,您可以使用「喜欢」按钮表达您的态度。 +- 不要刷帖。 这里是论坛,不是聊天室。 +- 如果您的回复偏题了,或者会导致整个讨论的方向发生转变,请考虑发起一个全新的讨论。 +- 如果您只是想发表一些废话,作为测试,请到[「测试」](https://discuss.flarum.org/t/sandbox)标签中发表。 +- 请确保您的回复能提供建设性的反馈和支持,以便建设一个惠及所有人的社区。 + +没有人会抱怨一次两次的笑话或者是抖机灵的评论。 我们喜欢快保持着轻松的气氛! 不过为了保证办事效率,请不要和讨论完全脱轨。 + +> 感谢 Dominion 帮助我们制定了这些准则。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..6a4bbcb38 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum 使用一个叫 [Composer](https://getcomposer.org) 的程序来管理其依赖包和扩展程序。 你需要 Composer 以实现: + +- 通过命令行安装或更新 Flarum +- 通过命令行安装、更新或删除 Flarum 扩展 + +本指南会简单阐述 Composer 的使用。 我们强烈建议查阅 [官方文档](https://getcomposer.org/doc/00-intro.md) 以获取更多信息。 + +:::tip 即刻测试 Flarum? + +在共享主机上,建议使用扩展管理器扩展而不是 Composer。 这是一个 Composer 的图形界面,允许您安装、更新和删除扩展,而无需使用 SSH。 您可以直接用一个归档安装 Flarum,而不需要 Composer。 在扩展管理器预装后,请检查[安装指南](install.md#installing-by-unpacking-an-archive)获取更多信息。 + +::: + +## 什么是 Composer? + +> Composer 是一个 PHP 依赖管理工具。 它允许您声明项目所依赖的库,并管理 (安装/更新) 这些库 。 — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +每次安装 Flarum 都包含了 Flarum 的核心和一系列的 [扩展](extensions.md) 他们都有自己的自己的依赖和发布包。 + +在过去,论坛框架会通过让用户上传带有拓展代码的压缩文件来管理拓展。 这看上去很简单,但问题会很快显现出来: + +- 通过网络上传随机的压缩文件通常是一个不好的主意。 要求扩展从像 [Packagist](https://packagist.org/) 这样的中央源头下载能够使得恶意代码的传播变得更加繁琐,并确保源代码在 GitHub 上对免费/公共扩展可用。 +- 比方说,扩展 A 需要某个库的第 4 版,而扩展 B 需要同一个库的第 5 版。 在基于压缩文件的解决方案中,这两个依赖中的任何一个都可能覆盖另一个,以造成各种不一致的问题。 或者两个都试图同时运行,这将导致 PHP 崩溃(同一个类不能声明两次)。 +- 如果试图自动部署,运行自动测试,或扩展到多个服务器节点,压缩文件会造成很多麻烦。 +- 我们无法确保冲突的扩展版本不被安装,或者确保系统的 PHP 版本和扩展要求被满足。 +- 当然,我们可以通过替换压缩文件来升级扩展。 但是,升级 Flarum 核心呢? 我们又如何确保扩展可以声明它们与哪些版本的核心兼容? + +Composer 解决了所有这些,乃至更多的问题! + +## Flarum & Composer + +当你去 [安装 Flarum](install.md#installing) 时,你实际上在做两件事。 + +1. 下载一个 Flarum 的模板“骨架”。 这包括一个处理网络请求的 `index.php` 文件,一个提供 CLI 的 `flarum` 文件,以及一系列的网络服务器配置和文件夹设置。 这是从[`flarum/flarum` github仓库](https://github.com/flarum/flarum)中提取的,实际上并不包含 Flarum 运行所需的任何代码。 +2. 安装 Flarum 所需的 `composer` 包,即 Flarum 核心和几个捆绑的扩展。 这些是由步骤 1 中的 `index.php` 和 `flarum` 文件调用的,是 Flarum 的实现。 这些都是在骨架中的 `composer.json` 文件中指定的。 + +当你想更新 Flarum 或添加/更新/删除扩展时,你将通过运行 `composer` 命令来实现。 每个命令都不同,但所有命令都遵循相同的一般流程: + +1. 更新 `composer.json` 文件来添加/删除/更新软件包。 +2. 如果可能的话,我们需要做一些计算以得知所有依赖的最新兼容版本,或者弄清楚为什么所要求的安排是不可能的。 +3. 如果一切正常,下载所有需要更新的东西的新版本。 如果遇到问题,你可以尝试恢复 `composer.json` 的更改。 + +当运行 `composer.json` 命令时,一定要注意输出信息。 如果有错误,它可能会告诉你是否是因为扩展程序不兼容,不支持的 PHP 版本,缺少 PHP 扩展程序,或其他原因。 + +### `composer.json` 文件 + +如上所述,整个 Flarum 网站的 composer 配置都包含在 `composer.json` 文件中。 你可以查阅 [composer 文档](https://getcomposer.org/doc/04-schema.md)以了解具体的模式,但现在,让我们看看来自 `flarum/flarum` 的 `composer.json` 注释: + +```json +{ + // 以下章节大部分只是关于包的元数据。 + // 对论坛管理员来说,这并不重要。 + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // 元数据结束 + + // 下面是我们最关心的部分 + // 这是我们想要的包清单和每个包的版本。 + // 我们会简单略过他们 + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Composer 的配置多种多样。 这是合理的默认值。 + // 您可在 https://getcomposer.org/doc/06-config.md 找到选项列表。 + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // 如果 composer 可以找到一个软件包的稳定(而非测试)版本, + // 它应当使用它。 一般来说,生产站点不应运行测试版软件, + // 除非你明白自己在做什么。 + "prefer-stable": true +} +``` + +让我们把重点放在 `require` 部分。 这个部分的每个条目都是一个 composer 包的名字和一个版本字符串。 要阅读更多关于版本字符串的信息,请参见相关的 [composer documentation](https://semver.org/)。 + +对于 Flarum 项目来说,在安装 `flarum/core` 的 `require` 字段中,你会看到有几种类型的条目: + +- 你必须有一个 `flarum/core` 节点。 这应该包含一个与您想要安装的版本相对应的明确的版本字段。 对于 1.x 版本的 Flarum,这应是 `^1.0`。 +- 你应该为你安装的每个扩展配备一个节点。 一些内置扩展(比如 `flarum/tags` 和 `flarum/suspend` 等)已被默认包含,[其他的由您通过 composer 指令添加](extensions.md)。 除非你有其它原因(比如正在测试一个包的测试版本),我们建议使用星号作为扩展的版本字段(`*`)。 它的意思是“安装与我的 flarum/core 相适配的最新版本”。 +- 某些扩展/功能可能需要 PHP 包,而不是 Flarum 扩展。 比如,你需要 guzzle 库来使用 [Mailgun 邮件驱动器](mail.md)。 在这种情况下,该扩展/功能的说明应该解释使用哪个版本字段。 + +## 如何安装 Composer? + +就像其他的软件一样,Composer需要先安装在你要安装Flarum的服务器上 这里有很多选项,取决于你使用网站服务的类型 + +### 独立服务器 + +在这种情况下,你可以安装Composer通过阅读[Composer Guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### 共享服务器 + +如果Composer没有预先安装(你可以通过执行`composer --version`命令来判断),你可以查阅[手动安装手册](https://getcomposer.org/composer-stable.phar) 只需要上传 composer.phar 到你的文件夹中,并执行`/path/to/your/php7 composer.phar COMMAND` 对于所有的命令应该以`composer COMMAND`执行 + +:::danger + +互联网上的一些文章会提到你可以使用像 PHP shell 这样的工具。 如果你不知道你在做什么或他们在说什么,请小心! 无保护的 web shell 是 **极危险的**。 + +::: + +## 如何使用 Composer + +你需要在命令行界面(CLI)上运行 Composer。 请确保你可以通过 SSH 访问你的服务器。 + +一旦你安装了 Composer,你应该能够通过 `composer COMMAND` 在您的 SSH 终端中运行 composer 命令。 + +:::info 优化 + +在大多数命令后,你可以运行 `composer dump-autoload -a`。 基本上,这会缓存 PHP 文件使他们运行得更快。 + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..e0331c835 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# 配置文件 + +除数据库外,只有一处配置是无法通过后台管理面板修改的,那就是位于 Flarum 安装根目录下的 `config.php` 文件。 + +虽然这个文件很小,但包含了 Flarum 安装时至关重要的信息。 + +如果存在这个文件,Flarum 就知道它自己已经被安装了。 另外这个文件还为 Flarum 提供数据库信息等内容。 + +下面是一个示例文件,我们来了解一下所有内容的含义: + +```php + false, // 启用或禁用调试模式,用于排查问题 + 'offline' => false, // 启用或禁用网站维护模式。这使得所有用户(包括管理员)无法访问您的网站。 + 'database' => + array ( + 'driver' => 'mysql', // 数据库驱动,例如 MySQL, MariaDB …… + 'host' => 'localhost', // 连接的主机,除非使用外部服务,否则多数情况下是 localhost + 'database' => 'flarum', // 数据库实例名 + 'username' => 'root', // 数据库用户名 + 'password' => '', // 数据库密码 + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // 数据表的前缀,如果您和其他服务共享一个数据库,那么添加前缀会很有用 + 'port' => '3306', // 连接数据库的端口,MySQL 默认为 3306 + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // URL 配置,如果您改变了域名,您需要变更这个 + 'paths' => + array ( + 'api' => 'api', // /api 跳转到 API + 'admin' => 'admin', // /admin 跳转到 admin + ), +); +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..3cbf42389 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# 控制台 + +除了 Flarum 核心提供的 [默认命令](../console.md),我们还允许扩展程序的开发者添加自定义控制台命令。 + +使用控制台: + +1. `ssh` 连接到安装 Flarum 的服务器 +2. `cd` 进入含有一个叫做 `flarum` 的文件的文件夹中 +3. 执行 `php flarum [命令名]` + +## 注册控制台命令 + +### list + +要注册控制台命令,请在您插件的 `extend.php` 文件中使用 `Flarum\Extend\Console` 扩展器: + +### help + +`php flarum help [命令名]` + +输出指定命令的帮助信息。 + +要以其他格式输出,请添加 --format 参数: + +`php flarum help --format=xml list` + +要显示可用的命令列表,请使用 list 命令。 + +### info + +`php flarum info` + +获取 Flarum 核心及已安装插件的信息。 调试问题时这个命令会很有用,在您提交的问题报告中也应当附上该输出内容。 + +### cache:clear + +`php flarum cache:clear` + +清楚后端 Flarum 缓存,包括已生成的 js/css,文本格式器缓存、翻译缓存。 这应当在每次安装或移除扩展后运行,在出现问题时这应该是第一步。 + +### assets:publish + +`php flarum migrate:reset --extension [插件ID]` + +发布核心和扩展插件中的资源文件(例如编译的 JS/CSS、bootstrap 图标、logos 等)。 这在您的资源文件发生损坏,或者您切换了 [文件系统驱动程序](extend/filesystem.md) 的 `flarum-assets` 存储磁盘时可以帮助您。 + +### 迁移 + +`php flarum migrate` + +执行所有未完成的迁移。 当安装或更新一个要修改数据库的插件时,会用到此命令。 + +### migrate:reset + +`php flarum migrate:reset --extension [插件ID]` + +重置指定插件的所有迁移。 这个命令大多被插件开发人员使用,如果您要卸载插件,并且想要从数据库中清除该插件的所有数据,也会需要用它。 请注意,该命令的被执行插件必须处于已安装状态(插件启用不启用都行)。 + +### schedule:run + +`php flarum schedule:run` + +许多扩展使用预定作业定期执行任务。 包括清理数据库缓存,定时发布草稿,生成站点地图等。 If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +这个命令一般不应被手动执行。 + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +此命令将返回已计划命令的列表(更多信息请参阅 `schedule:run`)。 这有助于确认扩展程序提供的命令已正确注册。 This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..4d4c78a3a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# 文档与翻译 + +## 补充文档 + +补充文档可以帮助无数未来的Flarum用户。 你可以在以下几点上下功夫: + +- 帮助Flarum最终用户使用一些高级Flarum功能的用户指南。 +- 更多 [常见问题](faq.md)。 +- 更加详细的 [故障排除](troubleshoot.md) 的步骤。 +- Flarum 开发或安装的逐步教程。 +- 扩展开发者的[技术参考指南](extend/README.md)。 +- 帮助我们提升你认为我们应该进一步阐述或更好地解释的其他事物。 + +找到相关主题的好方法是在我们社区的 [支持标签](https://discuss.flarum.org/t/support) 中寻找常见问题。 + +## 翻译Flarum + +我们希望每个人都能使用Flarum,不论其掌握的语言种类! 通过提供翻译,您可以让更多的人享受Flarum。 最好的是,我们使用方便用户的用户界面进行翻译,所以如果您想提供帮助,不需要硬性技术要求! + +Flarum Core的翻译、捆绑扩展和社区扩展是通过 [Weblate](https://weblate.rob006.net/projects/flarum/) 管理的。 + +此文档的翻译通过 [Crowdin](https://crowdin.com/project/flarum-docs) 管理。 + +Flarum基金会设立了“flarum-lang”组织,以支助笔译员以确保各种语言包的可用性。 您可以通过 [访问 GitHub 仓库](https://github.com/flarum-lang/about) 了解更多信息。 + +如果你想要支持现有的语言包,开始一项新的翻译,或者在使用weblate或crowdin时出现问题,您 [最好与 `flarum-lang` 团队](https://discuss.flarum.org/d/27519-the-flarum-language-project) 取得联系。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..db188b72f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# 贡献代码 + +有兴趣为 Flarum 的发展做贡献吗? 那太好了! 竭诚欢迎,[报告错误](bugs.md) 或是 Pull Request 都没问题! 没有我们社区的贡献,Flarum就不会有今天。 + +在贡献之前,请仔细阅读 [行为准则](code-of-conduct.md)。 + +本文档是想要为 Flarum 贡献代码的开发者的指南。 如果您只是入门,建议您阅读进阶文档中的 [Getting Started](https://flarum.org/extend/start.md) 文档了解 Flarum 的工作原理。 + +## 为什么要为Flarum做贡献? + +⚡ **作出实际影响。** 成千上万的Flarum实例,和数百万的累积最终用户, 都会因为你的贡献而受益。 + +🔮 **塑造Flarum的未来。** 我们有很长的待办事项列表,但时间有限。 如果你愿意成为一个特性或更新的代言人,它将更有可能发生,并且你将能够实现你的愿景。 此外,我们的路线图和里程碑是由我们 [的核心开发团队](https://flarum.org/team)设定的,我们所有人都是贡献者。 影响的最佳途径是贡献。 + +🧑💻 **成为更好的工程师。** 我们的代码库是现代化的,我们非常重视良好的工程和清晰的代码。 在设计、基础设施、性能和可扩展性方面,也有很多有趣、具有挑战性的问题需要解决。 特别的,如果你是一名学生或处于职业生涯的初期,参与 Flarum 的开发是一个培养开发技能的绝佳机会。 + +🎠 **很有趣!** 我们非常喜欢在 Flarum 上工作:有很多有趣的挑战和有趣的特性可以构建。 我们在[论坛](https://discuss.flarum.org)和 [Discord 服务器](https://flarum.org/chat)上也有一个活跃的社区。 + +## 开发设置 + +请查看我们的规划 [里程碑](https://github.com/flarum/core/milestones),了解一下需要做的事情。 您可以查看[「Good first issue」](https://github.com/flarum/core/labels/Good%20first%20issue)标签中的 Issue,这些 Issue 都比较容易上手。 有任何您不确定的问题,不要犹豫,直接提问! 我们曾经都是新手。 + +如果您打算揽下某项工作,请先在相关 Issue 上发表评论或创建一个新的 Issue 告知我们, 以免做无用功。 + +由于 Flarum 是如此依赖扩展,因此在处理核心问题以及捆绑扩展时,我们强烈推荐使用[我们的扩展文档](extend/README.md)作为参考。 你应该从[介绍](extend/README.md)开始,以更好地了解我们扩展中的学问。 + +## 开发流程 + +### 建立本地代码库 + +[flarum/flarum 是一个「骨架」应用程序,它使用 Composer 下载核心包 和 一堆扩展程序](https://github.com/flarum/flarum)。 Flarum 核心、扩展和前述使用的所有包的源代码都位于 Flarum Monorepo [flarum/framework ](https://github.com/flarum/framework)中。 若要对其进行贡献,你需要在本地 fork 和 clone Monorepo 代码库,然后将其作为 [Composer 路径库](https://getcomposer.org/doc/05-repositories.md#path)添加到开发环境中: + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# 或者,如果你想要直接克隆到当前目录: +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com/Hello!
+ } +} +``` + +### Setting Page as Homepage + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Page Titles + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..d2e0533a7 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,422 @@ +# 前端开发 + +这个页面描述如何改变Flarum的用户界面—— 添加按钮、文字滚动、和闪耀的文本 🤩 + +[记住](/extend/start.md#architecture), Flarum 的前端是**单页 JavaScript 应用**。 我们不会用到Twig、Blade或任何其他的PHP模板。 后端中存在的少数模板仅用于渲染针对搜索引擎优化的内容。 所有对UI的改动都需要通过JavaScript实现。 + +Flarum有两个分开的前端应用: + +* `forum`,论坛的公共部分,用户在此处创建讨论和帖子。 +* `admin`,论坛的私有部分,你作为论坛管理员在此处对Flarum进行配置。 + +它们共享相同的基础代码,所以只要你学会了如何拓展其中一个,你就能够拓展另一个。 + +:::tip 类型申明(typings)! + +我们在提供新的 TypeScript 支持的同时,提供了一个 [`tsconfig` 配置包](https://www.npmjs.com/package/flarum-tsconfig),你应该将它作为开发依赖安装,以查看我们的类型申明。 请确保你按照[配置包的README文件](https://github.com/flarum/flarum-tsconfig#readme)中的指示配置类型申明支持。 + +::: + +## 转译和文件结构 + +本教程的这个部分讲解释编写拓展的必要文件设置。 再说一次,我们高度推荐使用[Flarum CLI](https://github.com/flarum/cli)来为你创建文件结构。 话虽如此,你仍然应该阅读这一部分以理解文件结构背后的原理。 + +在我们编写JavaScript之前,我们需要配置**转译器**。 这使得我们可以在Flarum核心代码以及拓展中使用[TypeScript](https://www.typescriptlang.org/)和它的魔力。 + +为了进行转译,你需要一个好的工作环境。 不是说在家或者办公室这种环境——你想在厕所写代码我都不管! 我指的是安装在你系统上的工具。 你需要: + +* Node.js和npm ([下载](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +这可能比较麻烦,因为每个人的系统都不一样。 从您正在使用的操作系统,到您已安装的程序版本,到用户访问权限——想想就令人胆寒。 如果你遇上了困难,~~帮我向他问好~~ 上[谷歌](https://google.com)查查是否有人遇到了同样的问题并找到解决方案。 如果找不到,可以去[Flarum社区](https://discuss.flarum.org)或者[Discord群聊](https://flarum.org/discord/)寻求帮助。 + +是时候设置我们的小 JavaScript 转译项目了。 在你的扩展中创建一个新文件夹,名为 `js`,然后再丢进去几个新文件。 一个典型拓展的前端结构是这样的: + +``` +js +├── dist (编译后的js文件保存在此处) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +这是一个标准 JS [包描述文件](https://docs.npmjs.com/files/package.json),被 npm 和 Yarn (JavaScript 包管理器) 使用。 你可以使用它来添加指令、JS依赖和包元数据。 我们不是在真正发布一个npm包:这只是用来收集依赖项。 + +请注意,我们不需要将 `flarum/core` 或任何flarum扩展作为依赖:它们会在Flarum编译所有前端拓展时自动被打包。 + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/)是真正为我们的插件编译并打包所有Javascript (及其依赖) 的系统。 为了使我们的扩展正常工作,它应该使用 [官方的 flarum webpack 配置](https://github.com/flarum/flarum-webpack-config) (在上述例子中展示)。 + +### tsconfig.json + +```json +{ + //使用Flarum的tsconfig作为开始 + "extends": "flarum-tsconfig", + // 这会匹配你的 `src` 文件夹中所有的.ts、.tsx、.d.ts、.js和.jsx文件 + // 同时会让你的Typescript读取论坛核心的全局类型申明 + // 以获取全局命名空间中的`dayjs`和`$` + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // 这会让类型申明输出到 `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +├── models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### 导入 + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### 转译 + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Asset Registration + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..9da3f70b3 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# 搜索 + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..07e3e4d91 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Service Provider + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. [Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. The most common use case for service providers is to create, modify, or replace container bindings. That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..ffefdcde5 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Settings + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..ade6691da --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# 开始 + +想打造一个 Flarum 扩展? 来对地方了! 本文档将带您了解一些基本概念,之后您将从头开始打造您的第一个 Flarum 扩展。 + +## 架构 + +为了理解如何扩展 Flarum,我们需要先明白 Flarum 是如何构建的。 + +要知道,Flarum 使用了一些 _现代_ 语言和工具。 如果您以前只构建过 WordPress 的插件,您可能会觉得有点力不从心。 没有关系 —— 这是一个学习新事物和扩展技能的好机会。 不过我们建议您在开始之前先熟悉一下下面描述的技术。 + +Flarum 的构成有三层: + +* 第一层,**后端**。 后端用 [面向对象的 PHP 语言](https://laracasts.com/series/object-oriented-bootcamp-in-php)编写,并通过 [Composer](https://getcomposer.org/) 使用了大量的 [Laravel](https://laravel.com/) 组件和其他资源包。 您还需要熟悉 [依赖项注入](https://laravel.com/docs/6.x/container) 的概念,它在整个后端中都有使用。 + +* 第二层,后端开放的一个 **公共 API**,允许前端客户端与论坛数据进行交互。 该接口根据 [JSON:API 规范](https://jsonapi.org/) 构建。 + +* 第三层,默认的 Web 界面,俗称 **前端**。 这是一个使用 API 的 [单页应用](https://en.wikipedia.org/wiki/Single-page_application), 由一个简单的类 React 框架 [Mithril.js](https://mithril.js.org/) 构建。 + +扩展程序通常需要与这三层都进行交互才能有所为。 例如,如果您想创建一个可以在用户资料中添加新属性的扩展,则需要在 **后端** 中添加相应的数据库结构,通过 **公共 API** 调用该数据,然后在 **前端** 显示这个数据并允许用户修改它。 + +那…… 如何扩展这些层呢? + +## 扩展器 + +为了扩展 Flarum,我们需要用到 **扩展器**,让我们先了解一下它的概念。 扩展器其实就是 *声明性* 对象,您可以通过简单的方式描述想要实现的内容(比如向论坛添加新的路由,或者在创建新主题帖时执行某些代码)。 + +每个扩展器都是不同的, 但是大体上长这样: + +```php +// 注册要交付给前端的 JavaScript 和 CSS 文件 +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +您首先创建一个扩展器实例,然后调用方法以对其进行进一步配置。 所有方法都将返回结果到该扩展器本身,因此您只需要通过链式方法调用就可以实现您的整个配置。 + +为了保持一致,我们在后端(PHP)和前端(JavaScript)都使用了扩展器的概念。 您在扩展中做的 _每一件事_ 都应当通过扩展器来完成,因为扩展器是我们给予您的 **保证** —— 保证 Flarum 小版本更新绝对不破坏您的扩展。 + +所有 Flarum 核心提供的可用扩展器都可以在 [`Extend` 命名空间](https://github.com/flarum/framework/blob/main/framework/core/src/Extend)[(PHP API 文档)](https://api.docs.flarum.org/php/master/flarum/extend)中找到。扩展程序亦有可能提供他们[自有的扩展器](extensibility.md#custom-extenders)。 + +## 世界你好 + +想亲眼看看一个扩展器的执行? Flarum 安装根目录中的 `extend.php` 是为您的站点注册扩展器的最简单的途径,它应该会返回一个扩展器对象的数组。 它应该会返回一个扩展器对象的数组。 打开该文件并添加以下内容: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +现在,访问您的论坛,接受真挚的问候(尽管很突兀)。 👋 + +对于简单的网站定制,比如添加一些自定义的 CSS 或 JavaScript,或者整合您网站的认证系统,论坛根目录下的 `extend.php` 文件是非常好用的。 但是在某些时候,您的自定义可能会超出它的限制范围。 或者您想建立一个扩展程序,并分享到社区。 那么是时候建立一个扩展程序了! + +## 打包扩展程序 + +[Composer](https://getcomposer.org) 是 PHP 的一个依赖管理工具。 它允许应用程序轻松地拉取外部代码库,并保持他们是最新的,以便及时应用安全补丁和错误修复。 + +如上所述,每个 Flarum 扩展程序也是一个 Composer 包。 这意味着一个人可以「require」某个扩展程序,Composer 会把它拉取给 Flarum,同时使扩展程序保持最新版本。 Nice! + +在开发过程中,您可以在本地处理您的扩展程序,并建立一个 [Composer 本地路径仓库](https://getcomposer.org/doc/05-repositories.md#path) 以安装您的本地副本。 在 Flarum 安装根目录下创建一个新的 `packages` 文件夹,然后运行这个命令来告诉 Composer 它可以在这里找到软件包: + +```bash +composer config repositories.0 path "packages/*" +``` + +现在,来构建我们的第一个扩展程序吧。 在 `packages` 里面为您的扩展程序建立一个新的文件夹,命名为 `hello-world`。 我们会在里面放两个文件:`extend.php` 和 `composer.json`。 这些文件是扩展程序的心脏和灵魂。 + +### extend.php + +扩展程序的 `extend.php` 跟您站点根目录下的那个是一模一样的。 它会返回一个扩展器对象数组,并告诉 Flarum 您想要做什么。 现在,将前面我们操作的 `Frontend` 扩展器移动到这里。 + +### composer.json + +我们需要告诉 Composer 一些您的软件包的信息,创建 `composer.json` 文件已写入这些信息: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "向世界问好!", + "type": "flarum-extension", + "require": { + "flarum/core": ">=0.1.0-beta.16 <=0.1.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name**,名字。 是 Composer 软件包的名字。 格式是 `供应商/包名`。 + * 您需要起一个全世界独一无二的供应商名,或者可以直接沿用 GitHub 的用户名。 以本教程为例,这里我们假设 `acme` 是您的供应商名。 + * 您应该给包 `包名` 加上 `flarum-` 前缀,以指明此包是专门给 Flarum 用的。 + +* **description**,描述。 用一句话描述这个扩展程序的作用是什么。 + +* **type**,类型。 只能是 `flarum-extension`。 这确保了当别人「require」您的扩展程序时,能被正确识别。 + +* **require**,依赖。 描述您的扩展程序自身的依赖关系。 + * 您需要在这里指定您的扩展程序所兼容的 Flarum 版本。 + * 这里也是列出您的代码需要使用的 Composer 外部工具库的地方。 + +* **autoload**,定义一个从命名空间到目录的映射,告诉 Composer 在哪里可以找到扩展程序的类。 此处的命名空间应以 驼峰写法 反映扩展程序的供应商和包名. + +* **extra.flarum-extension**,包含一些 Flarum 特有的信息,比如您扩展程序在论坛的显示名称以及图标。 + * **title** 您的扩展程序的显示名称。 + * **icon** 是一个定义您扩展程序图标的对象。 **name** 属性是 [Font Awesome 图标名](https://fontawesome.com/icons)。 剩下的都被用作图标的 `style` 属性。 + +请参阅 [composer.json 模式](https://getcomposer.org/doc/04-schema.md) 文档,以获取有关可以添加到 `composer.json` 中的其他属性的信息。 + +:::info [Flarum CLI](https://github.com/flarum/cli) + +使用 [FoF 扩展生成器](https://github.com/FriendsOfFlarum/extension-generator) 自动创建扩展程序的基架。 +```bash +$ flarum-cli init +``` + +::: + +### 安装您的扩展 + +最后一步就是安装您的扩展。 进入 Flarum 安装根目录,执行以下命令: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +执行完成后,前往您论坛后台管理面板启用插件,最后回到您的论坛。 + +*啾,咻,铮铛* + +哇! 你好,扩展! + +很好,我们取得了一些进展。 我们学习了如何设置扩展和使用扩展,打开了新世界的大门。 继续阅读以了解如何扩展 Flarum 的前端。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..b1342ede0 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# 测试 + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + +something
Hello World!
; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return{this.counter}
; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +{this.attrs.counter}
; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +Counter: {app.counter.getCount()}
+Hello World!{this.showContent ? ' Extra Content!' : ''}
+Hello World!
你好,世界!
" + } + }, + // [...] 其他包含内容 + ] +} +``` + +### 发布主题 + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "这里是标题", + "content": "你好,世界!" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +服务器响应含有新主题的 ID: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "这里是标题", + "slug": "42-gu-ding-lian-jie", + "commentCount": 1 + // [...] 其他属性 + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] 其他关联内容 + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003E你好,世界!\u003C\/p\u003E" + // [...] 其他属性 + } + } + // [...] 其他包含内容 + ] +} +``` + +### 注册用户 + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "YongHuMing", + "email": "flarum@example.com", + "password": "MiMa" + } + } +} +``` + +## 错误 + +Flarum 使用不同的 HTTP 状态码进行错误应答,所有错误表述均符合 [JSON:API 错误规范](https://jsonapi.org/format/#errors)。 + +下面是您使用 REST API 时可能遇到的一些常见错误: + +### CSRF 令牌不匹配 + +如果您收到了消息为 `csrf_token_mismatch` 的 400 HTTP 错误,这意味着 `Authorization` 请求头缺失或无效,导致 Flarum 尝试通过会话 Cookie 进行身份验证。 + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### 验证错误 + +验证错误会返回一个 HTTP 状态码 422 的响应。 无效字段的名称会以 `pointer` 值返回。 在同一时间,单个字段可能出现多个错误。 + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", // 用户名已被使用 + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", // 邮箱地址已被使用 + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..1a0b24913 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# 调度器 + +Flarum的调度器让扩展程序能够轻松地自动化某些任务。 在本指南中,我们将介绍如何设置它。 我们不会深入讨论cron本身的细节,但如果你想进一步了解它,我建议你查看[Wikipedia上关于cron的文章](https://en.wikipedia.org/wiki/Cron)。 + +## 为什么我要关心? + +很简单,现在有越来越多的扩展程序支持在后台自动为你处理某些功能。 想知道为什么`fof/drafts`的“定时发布”没有发布,抑或是`fof/best-answer`的“在X天后提醒用户设置最佳答案”功能没有被触发吗? 那是因为它们会自动用调度器服务来配置自己,但这一切配置的前提是一行简短的cron任务。 + +## 有什么扩展程序现在在使用调度器? + +最火的一些例子如下: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## 让我们配置起来! + +几乎所有(全部)Linux发行版本都自带或可以安装cron。 例如,在基于Debian和Ubuntu的系统上,你可以这样安装`cron`: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +如果你使用的是基于RHEL的Linux发行版(如CentOS、AlmaLinux、Rocky Linux等),可以这样安装cron: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +安装好了cron,让我们创建Flarum所需的唯一定时条目: + +``` +crontab -e +``` + +这将打开 cron 编辑器。 你或许会有其他 cron 条目,但没关系。 添加以下这行,并记住在底部留一个空行。 + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` 会告诉 cron 每分钟都来运行你的命令。 + +如果你想修改触发时间,但不确切知道 cron 表达式是如何工作的,你可以使用[cron表达式生成器](https://crontab.guru)来轻松获取所需的命令。 + +`cd /path-to-your-project && php flarum schedule:run` 这行代码将执行Flarum的调度器以触发当前所有等待运行的任务。 如果PHP不在你的系统路径中,你可能需要尝试设置PHP的完整路径。 + +最后,`>> /dev/null 2>&1` 抑制了命令的所有输出。 + +瞧! 现在任何注册了定时任务的扩展程序,从每分钟到每天、每月、每年,都将自动在你的服务器上运行。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/tags.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/tags.md new file mode 100644 index 000000000..cba515c89 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/tags.md @@ -0,0 +1,3 @@ +# 分类目录和标签 +此页面正在建设中。 +This page is under construction. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..318e55c86 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# 样式主题 + +尽管我们一直在努力使 Flarum 变得尽可能美丽,但每个社区可能都希望进行一些调整/修改,以适合他们所需的风格。 + +## 管理面板 + +[管理面板](admin.md) 的「外观」页面是自定义论坛的绝佳起点。 在这里,您可以: + +- 选择主题颜色 +- 切换夜间模式和彩色导航栏。 +- 上传标志和站点图标(浏览器标签中显示的图标)。 +- 在自定义页眉和页脚添加 HTML。 +- 添加 [自定义LESS/CSS](#css-主题) 来改变元素的显示方式。 + +## CSS 主题 + +CSS 是一种样式表语言,它告诉浏览器如何显示网页的元素。 它允许我们修改所有的东西,从颜色到字体到元素的大小,从定位到动画等等。 添加自定义 CSS 是修改您的 Flarum 默认主题的好方法。 + +CSS 教程不在本文档的讨论范围之内,但是有大量的优质在线资源可供您学习 CSS 的基础知识。 + +:::tip + +Flarum 其实使用了 LESS,它支持变量、条件和函数,可以让您更轻松地编写 CSS。 + +::: + +## 扩展 + +Flarum 灵活的 [扩展系统](extensions.md) 允许您添加、删除或修改 Flarum 的任何部分。 如果您想做实质性的主题修改,除了改变颜色/大小/样式之外,一个自定义的扩展绝对是您的最佳选择。 要学习如何制作扩展,请查看我们的 [扩展文档](extension/README.md)! diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..c660d9f53 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# 故障排查 + +如果 Flarum 没有按照预期那样安装或工作,您 *首先应该检查* 服务器环境是否符合 [系统要求](install.md#环境要求)。 如果您缺少一些 Flarum 运行所需的东西,请先补全内容。 + +然后,请花几分钟时间搜索 [支持论坛](https://discuss.flarum.org/t/support)和 [问题跟踪器](https://github.com/flarum/core/issues),有可能该问题已被报告,并且有了解决办法。 有可能已经有人报告了该问题,而且修复方案已经可用或正在开发中。 如果您彻底搜索后,仍然没有找到任何有用的信息,那么就可以开始排查故障了。 + +## 步骤 0:开启调试模式 + +:::danger 在生产环境下跳过 + +这些调试工具非常有用,但可能会暴露不应公开的信息。 如果你在暂存或开发环境中,这些是可以的。但是如果你不知道你在做什么,那么请在生产环境中跳过这个步骤。 + +::: + +在继续前,您应当启用 Flarum 的调试模式。 用文本编辑器打开 **config.php**,将 `debug` 的值改为 `true`,然后保存文件即可。 开启后,Flarum 会显示详细的错误报告,方便您了解到底发生了什么。 + +如果上面的改动不起任何作用,并且论坛所有页面都变成空白,请试试将 **php.ini** 文件中的 `display_errors` 设置为 `On`。 + +## 步骤 1:常见问题修复 + +很多问题都可通过以下解决: + +* 清除浏览器缓存。 +* 使用 [`php flarum cache:clear`](console.md) 清除后端缓存。 +* 确保以使用 [`php flarum migrate`](console.md) 更新数据库。 +* 确保 [邮箱配置](mail.md) 可用:无效的邮箱配置将导致注册、重置密码、更换用户绑定邮箱以及发送通知时产生错误。 +* 检查 `config.php` 配置是否正确,请确保您使用了正确的 `url`。 例如,请确保正在使用正确的 `URL`(`https` 与 `http` 或大小写敏感之类的,这很重要!) +* 罪魁祸首还可能是自定义页眉、自定义页脚或自定义 LESS。 如果你的问题在前端,请尝试通过删除管理员仪表板中外观页面的设置。 + +您也得看看 [`php flarum info`](console.md) 的输出,以确保没有什么大的问题。 + +## 步骤 2:问题重现 + +请尝试让问题重现。 注意问题发生时,您在做什么? 是每次都会出现问题,还是仅偶尔出现? 尝试调整您觉得可能影响问题出现的设置或参数,或者改变您的操作顺序看看。 问题是否在某些情况下会出现,而在某些情况下又不会出现? + +如果您最近安装或更新了一个扩展程序,请暂时禁用它,然后看看问题有没有消失。 请确保您启用的所有扩展程序兼容您使用的 Flarum 版本。 过时的扩展会导致各种各样的问题。 + +在这个过程中,您可能会发现导致问题的原因,并找到了解决办法。 即便没有,您也可能会得到一些有价值的线索,您最好在报告中填写好这些信息,这将帮助我们弄清楚出了什么问题。 + +## 步骤 3:收集信息 + +如果您无法解决问题,需要他人的帮助,那么就是时候认真收集数据了。 请从这些地方搜集相关报错内容或其他与问题有关的信息: + +* 论坛页面上显示的报错 +* 浏览器控制台中显示的报错(Chrome:更多工具 -> 开发者工具 -> Console) +* 服务器错误日志中记录的内容(例如:`/var/log/nginx/error.log`) +* PHP-FPM 错误日志中记录的内容(例如:`/var/log/php7.x-fpm.log`) +* Flarum 日志记录的报错(`storage/logs/flarum.log`) + +将收集到的所有信息复制到记事本中,整理好并做一些注解,比如错误是 *何时* 发生的、当错误发生时您在 *做什么*、您探索出来的问题发生和不发生的条件。 请务必附加上你已经知道的关于问题复现条件的信息。 请尽可能详尽地提供服务器环境信息,如操作系统版本、Web 服务器版本、PHP 版本和处理程序等。 + +## 步骤 4:准备报告 + +竭尽所能收集相关问题的所有信息后,您就可以提交错误报告了。 提交时请遵循 [提交 Bug](bugs.md) 的有关说明。 + +如果您在提交报告后有发现新的情况,请添加到您的原始帖子底部。 倘若您已经自行解决了问题,也最好提交一份报告,说不定能帮助到遇到同样问题的其他用户。 如果您找到了临时的解决办法,也请告诉我们。 \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..713ac769f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# 更新 + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +您需要使用 [Composer](https://getcomposer.org) 来更新 Flarum。 如果你不熟悉它(尽管你应该是熟悉的,因为你需要它来安装Flarum),阅读 [我们的指南](composer.md) 了解它是什么以及如何设置它。 + +如果跨主要版本进行更新(如 <=0.1.0 to 1.x.x, 1.x.x 到 2.x.x.x, ... ),请确保在运行一般升级步骤之前阅读相应的“主要版本更新指南”。 + +## 一般步骤 + +**第1步:**确保你所有的扩展程序的版本与你要安装的Flarum版本兼容。 这只在主要版本之间需要(例如,如果从v1.0.0升级到v1.1.0,你可能不需要检查这个,假设你使用的扩展遵循建议的版本划分)。 你可以通过查看扩展的[讨论贴](https://discuss.flarum.org/t/extensions),在[Packagist](http://packagist.org/)上搜索它,或者查看[Extiverse](https://extiverse.com)等数据库来检查。 在更新之前,您需要删除(不仅仅禁用) 任何不兼容的扩展。 请耐心等待扩展开发者更新! + +**第2步:** 查看您的 `composer.json` 文件。 除非您有理由要求特定版本的扩展或库; 您应该将除 `flarum/core` 以外的所有版本字符串设置为 `*` (包括 `flarum/tags`, `flarum/mention`和其他捆绑的扩展)。 但请确认 `flarum/core` 未设置为 `*`。 如果你针对的是特定版本的Flarum, 请设置 `flarum/core` 为指定版本(例如, `"flarum/core": "v0.1.0-bet.16`)。 如果你只想要最新的版本,请使用 `"flarum/core": "^1.0"`。 + +**第 3步:** 如果您使用 [本地扩展](extenders.md),请确保它们更新到最新的 Flarum 中的变更。 + +**第 4 步:** 我们建议在更新之前在管理面板禁用第三方扩展。 这不是严格需要的,但如果您遇到问题,将更容易调试问题。 + +**第 5步:** 请确保您的 PHP 版本被您正在尝试升级到 Flarum 的版本所支持。 并且你正在使用Composer 2(`composer --version)` + +**步骤6:** 最后更新,运行: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**步骤7:** 如果可以,请重启您的 PHP 进程和opcache。 + +## 主要版本更新指南 + +### 从 Beta (<= 0.1.0) 更新到 Stable v1 (^1.0.0) + +1. 执行上文步骤1-5。 +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## 故障排除 + +Flarum 正处于测试阶段,有关如何更新的说明将在每次 [版本发布公告](https://discuss.flarum.org/t/blog?sort=newest)中公示。 + +### 更新时出错 + +这里我们将会处理尝试更新 Flarum 时出现的几种常见问题。 + +--- + +如果输出较短且包含: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +如果输出看起来像这样: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +如果您在更新后无法访问您的论坛,请遵循我们的 [故障排除说明](troubleshoot.md)。 diff --git a/versioned_docs/version-1.x/README.md b/versioned_docs/version-1.x/README.md new file mode 100644 index 000000000..45d90f93e --- /dev/null +++ b/versioned_docs/version-1.x/README.md @@ -0,0 +1,45 @@ +--- +slug: / +--- + +# About Flarum + +Flarum is a delightfully simple discussion platform for your website. It's fast, free, and easy to use, with all the features you need to run a successful community. It's also extremely extensible, allowing for ultimate customizability. + + + +## Goals + +Flarum is the combined successor of [esoTalk](https://github.com/esotalk/esoTalk) and [FluxBB](https://fluxbb.org). It is designed to be: + +* **Fast and simple.** No clutter, no bloat, no complex dependencies. Flarum is built with PHP so it’s quick and easy to deploy. The interface is powered by [Mithril](https://mithril.js.org), a performant JavaScript framework with a tiny footprint. + +* **Beautiful and responsive.** This is forum software for humans. Flarum is carefully designed to be consistent and intuitive across platforms, out-of-the-box. + +* **Powerful and extensible.** Customize, extend, and integrate Flarum to suit your community. Flarum’s architecture is amazingly flexible, with a [powerful Extension API](/extend/README.md). + +* **Free and open.** Flarum is released under the [MIT license](https://github.com/flarum/flarum/blob/master/LICENSE). + +You can read more about our [philosophy and values for Flarum here](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values). + +## Help the Flarum Project + +Flarum is [free, open source](https://github.com/flarum/core) software, maintained and governed by volunteers. We rely on community contributions to help us improve and expand Flarum. + +🧑💻 If you're a developer, consider [contributing to Flarum's core or bundled extensions](contributing.md). This is **the** most efficient way to help Flarum, and your work can have a lot of impact: there are thousands of Flarum sites out there, with millions of total end users. + +🧩 If there's a feature you're missing, or a theme idea you have, [writing a custom extension](extend/README.md) will make Flarum that much better for you and others. + +✒️ If you're experienced in technical writing, your contributions to [our documentation](https://github.com/flarum/docs/issues) could help future users, admins, and developers make the most of Flarum. + +🌐 If you speak multiple languages, you could [contribute translations](extend/language-packs.md) to could help make Flarum accessible to countless users around the world. + +💸 The Flarum Foundation doesn't make money off of Flarum, but does have bills to pay. Donations via [GitHub Sponsors](https://github.com/sponsors/flarum) or [OpenCollective](https://opencollective.com/flarum) are always gratefully received. In the past, we've also been able to support some of our core developers financially, so they could work on Flarum part time. This wouldn't be possible without your financial support. + +🧑🤝🧑 Join [our community](https://discuss.flarum.org) to talk about Flarum development, get help with your instance, or just meet cool people! If you're experienced with Flarum, you can also help out beginners! + +🐛 If there's a bug that's bothering you, or a feature idea on your mind, we can't know about it unless you tell us! We track bugs, suggestions, and future development plans [via GitHub issues](https://github.com/flarum/core/issues). If there's already an issue open, adding likes and (constructive) additional information can be very helpful! + +📣 And if you like Flarum, please consider blogging/tweeting/talking about it! More people aware of Flarum leads to more people engaging with Flarum, and therefore more activity, better extensions, and faster development. + +Flarum wouldn't be possible without our phenomenal community. If you're interested in contributing, see our [developer contribution](contributing.md) and [other contribution](contributing-docs-translations.md) docs for more information. diff --git a/versioned_docs/version-1.x/admin.md b/versioned_docs/version-1.x/admin.md new file mode 100644 index 000000000..c412a14b7 --- /dev/null +++ b/versioned_docs/version-1.x/admin.md @@ -0,0 +1,15 @@ +# Admin Dashboard + +The Flarum Admin Dashboard is a user-friendly interface for managing your forum. +It is only available to users in the "Admin" group. +To access the Admin dashboard, Click on your **Name** at the at the top right of the screen, and select **Administration**. + +The Admin Dashboard has the following sections, being: +- **Dashboard** - Shows the main Admin Dashboard, containing statistics and other relevant information. +- **Basics** - Shows the options to set basic forum details such as Name, Description, and Welcome Banner. +- **Email** - Allows you to configure your E-Mail settings. Refer [here](https://docs.flarum.org/mail) for more information. +- **Permissions** - Shows the permissions for each user group, and allows you to configure global and specific scopes. +- **Appearance** - Allows you to customize the forum's colors, branding and add additional CSS for customization. +- **Users** - Provides you with a paginated list of all the users in the forum, and grants you the ability to edit the user or take administrative actions. + +Apart from the above mentioned sections, the Admin Dashboard also allows you to manage your Extensions (including the flarum core extensions such as Tags) under the _Features_ section. Extensions which modify the forum theme, or allow you to use multiple languages are categorized under the _Themes_ and _Languages_ section respectively. diff --git a/versioned_docs/version-1.x/bugs.md b/versioned_docs/version-1.x/bugs.md new file mode 100644 index 000000000..85e8ea193 --- /dev/null +++ b/versioned_docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Reporting Bugs + +:::danger Security Vulnerabilities + +If you discover a security vulnerability within Flarum, please follow our [security policy](https://github.com/flarum/core/security/policy) so we can address it promptly. + +::: + +Thank you for helping us test Flarum. We're happy to have you on the team! We need people who can *troubleshoot issues patiently* and *communicate them clearly*. As you probably know, good bug reporting takes some time and effort. If you're fine with that, then let's get started! + +## Duplicates + +Found a bug already? Wonderful! We'd love to hear about it — but first you should check around to make sure you're not wasting your time on a known issue: + +- Search our [Support forum](https://discuss.flarum.org/t/support) to see if it's already been reported. +- We could be working on a fix, so search our [issue tracker](https://github.com/flarum/core/issues) too. + +If you've searched *thoroughly* and come up empty-handed, we'll welcome your report. If it's just a simple issue (a misspelled word or graphics glitch, for example) skip to the next paragraph. But if you're seeing errors, or something is clearly broken, we'll need you to gather some information first. Please head over to our [Troubleshooting](troubleshoot.md) guide and follow the instructions there. Collect as much info as you can! + +## Reporting + +We track issues on GitHub. Make sure you open your issue in the [correct repository](https://github.com/flarum), and fill out all of the information in the Bug Report template. + +If you can, check if the issue is reproducible with the latest version of Flarum. If you are using a pre-release or development version, please indicate the specific version you are using. + +Remember: the goal of a bug report is to make it easy for us to replicate the bug and fix it. You might want to read [this article](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for some useful tips on how to write an effective bug report. It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear reproduction steps will not be triaged. If an issue labeled "needs verification" receives no further input from the issue author for more than 5 days, it will be closed. + +Once you've posted your report, we'd ask that you please *follow the discussion* and wait patiently. We may need to ask for further details or clarification; but we've always got plenty to do, and it could be a while before we can give your report the time it deserves. diff --git a/versioned_docs/version-1.x/code-of-conduct.md b/versioned_docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..1faf10eea --- /dev/null +++ b/versioned_docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Code of Conduct + +### _Welcome to the Flarum Community!_ + +... And thanks for joining us! We're excited about Flarum, and are always happy to meet people who feel the same way. We want *everyone* to get the most out of Flarum and the Flarum community, so we ask that you please read and follow these guidelines. These apply whether you're using our forum, Discord chat, communicating on GitHub, or any other form of communication without the Flarum community. + +### Above All, Be Cool! + +We're all here to talk about Flarum, and to work together toward making it an even better application. Criticizing ideas (by means of reasoned arguments, of course) is an important part of that. But let's not get carried away and devolve into personal attacks, because negativity only gets in the way. We ask that you avoid the following: + +- Offensive or abusive language, as well as any kind of hate speech +- Posts intended to harass, impersonate, or defame others +- Unnecessary deletion of posted content +- Attempts to abuse or expose the private information of others +- Obscene or sexually explicit content +- Spam, phishing posts, and any actions intended to deface this site +- Discussion of software piracy and similar topics + +*All the above are grounds for moderator action.* If you have an issue with another member, we ask that you please don't confront them yourself. If it's on the forum, please use the *Report* command on the post in question, then leave it up to the staff to deal with the situation. Otherwise, report the violation using our [contact page](https://flarum.org/foundation/contact), option Legal. + +Our moderators may edit or delete any content that is offensive or disruptive to the flow of communication. Serious or repeated offenses may lead to suspension of the offending user's account. So, you know, *be cool*. 😎 + +### Make Yourself Heard + +Want to start a new discussion? First, be sure to read [our FAQ](faq.md) and follow the links to make sure you're fully informed about the project. Then spend some time browsing the forum, familiarize yourself with [the tag system](https://discuss.flarum.org/tags), and do a few searches for keywords related to your topic: *it could be someone has already started a discussion about it!* + +When you're sure you're ready to start a discussion, please keep the following points in mind: + +- Give it a good title! You'll get the best results if your title makes it clear what you want to talk about. +- Choose the right tag(s). This will increase the likelihood your post will be read and answered promptly. +- *Don’t* post repeatedly about the same topic, as doing so will tend to have the opposite effect. +- If not using a tag set aside for multilingual use, *post in English only.* We can't help you if we don't understand your posts. +- Remember, you don't need to sign your posts. We've got your profile to let us know who you are. + +Please make the effort to help us keep things organized. Time spent tidying up is time that we can't spend getting to know you, discussing your issues, and talking about Flarum. And that, after all, is what we're all here to do! + +### Make Your Reply Count + +You're taking the time to participate in a discussion, in the hope that others will read your ideas and take them into consideration. So why not make the effort to make your reply worth reading? + +- Don't reply to a title. Take some time to *read* the OP, and at least *scan* the rest of the conversation first. +- Ask yourself if your reply adds to the discussion. If it doesn't, give it some more thought before posting. +- Avoid making one-word posts just to agree with someone; you can use the "Like" button for that. +- Avoid making multiple posts in a row when one would suffice. This is a forum, not a chat room. +- If your reply is likely to divert the course of the discussion, consider starting a new discussion instead. +- If you just want to post a bit of nonsense as a test, please do it in the [Test Posting](https://discuss.flarum.org/t/sandbox) tag instead. +- Make sure your replies provide constructive feedback and support to allow for an inclusive community. + +No one's going to complain about the occasional joke or smart remark. We like to keep the mood light! But to keep things productive, as well, we ask that you try to avoid derailing a discussion altogether. + +> Thanks to Dominion for his help in putting these guidelines together. diff --git a/versioned_docs/version-1.x/composer.md b/versioned_docs/version-1.x/composer.md new file mode 100644 index 000000000..627f81821 --- /dev/null +++ b/versioned_docs/version-1.x/composer.md @@ -0,0 +1,155 @@ + +# Composer + +Flarum uses a program called [Composer](https://getcomposer.org) to manage its dependencies and extensions. +You'll need to use composer if you want to: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +This guide is provided as a brief explanation of Composer. We highly recommend consulting the [official documentation](https://getcomposer.org/doc/00-intro.md) for more information. + +:::tip Shared Hosting + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. +You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## What is Composer? + +> Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Each Flarum installation consists primarily of Flarum core and a set of [extensions](extensions.md). Each of these has its own dependencies and releases. + +Back in the day, forum frameworks would manage extensions by having users upload zip files with the extension code. That seems simple enough, but issues quickly become evident: + +- Uploading random zip files from the internet tends to be a bad idea. Requiring that extensions be downloaded from a central source like [Packagist](https://packagist.org/) makes it somewhat more tedious to spam malicious code, and ensures that source code is available on GitHub for free/public extensions. +- Let's say Extension A requires v4 of some library, and Extension B requires v5 of that same library. With a zip-based solution, either one of the two dependencies could override the other, causing all sorts of inconsistent problems. Or both would attempt to run at once, which would cause PHP to crash (you can't declare the same class twice). +- Zip files can cause a lot of headache if trying to automate deployments, run automated tests, or scale to multiple server nodes. +- There is no good way to ensure conflicting extension versions can't be installed, or that system PHP version and extension requirements are met. +- Sure, we can upgrade extensions by replacing the zip file. But what about upgrading Flarum core? And how can we ensure that extensions can declare which versions of core they're compatible with? + +Composer takes care of all these issues, and more! + +## Flarum and Composer + +When you go to [install Flarum](install.md#installing), you're actually doing 2 things: + +1. Downloading a boilerplate "skeleton" for Flarum. This includes an `index.php` file that handles web requests, a `flarum` file that provides a CLI, and a bunch of web server config and folder setup. This is taken from the [`flarum/flarum` github repository](https://github.com/flarum/flarum), and doesn't actually contain any of the code necessary for Flarum to run. +2. Installing `composer` packages necessary for Flarum, namely Flarum core, and several bundled extensions. These are called by the `index.php` and `flarum` files from step 1, and are the implementation of Flarum. These are specified in a `composer.json` file included in the skeleton. + +When you want to update Flarum or add/update/remove extensions, you'll do so by running `composer` commands. Each command is different, but all commands follow the same general process: + +1. Update the `composer.json` file to add/remove/update the package. +2. Do a bunch of math to get the latest compatible versions of everything if possible, or figure out why the requested arrangement is impossible. +3. If everything works, download new versions of everything that needs to be updated. If not, revert the `composer.json` changes + +When running `composer.json` commands, make sure to pay attention to the output. If there's an error, it'll probably tell you if it's because of extension incompatibilities, an unsupported PHP version, missing PHP extensions, or something else. + +### The `composer.json` File + +As mentioned above, the entire composer configuration for your Flarum site is contained inside the `composer.json` file. You can consult the [composer documentation](https://getcomposer.org/doc/04-schema.md) for a specific schema, but for now, let's go over an annotated `composer.json` from `flarum/flarum`: + +```json +{ + // This following section is mostly just metadata about the package. + // For forum admins, this doesn't really matter. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // It's a list of packages we want, and the versions for each. + // We'll discuss this shortly. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Various composer config. The ones here are sensible defaults. + // See https://getcomposer.org/doc/06-config.md for a list of options. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // If composer can find a stable (not dev, alpha, or beta) version + // of a package, it should use that. Generally speaking, production + // sites shouldn't run beta software unless you know what you're doing. + "prefer-stable": true +} +``` + +Let's focus on that `require` section. Each entry is the name of a composer package, and a version string. +To read more about version strings, see the relevant [composer documentation](https://semver.org/). + +For Flarum projects, there's several types of entries you'll see in the `require` section of your root install's `flarum/core`: + +- You MUST have a `flarum/core` entry. This should have an explicit version string corresponding to the major release you want to install. For Flarum 1.x versions, this would be `^1.0`. +- You should have an entry for each extension you've installed. Some bundled extensions are included by default (e.g. `flarum/tags`, `flarum/suspend`, etc), [others you'll add via composer commands](extensions.md). Unless you have a reason to do otherwise (e.g. you're testing a beta version of a package), we recommend using an asterisk as the version string for extensions (`*`). This means "install the latest version compatible with my flarum/core". +- Some extensions / features might require PHP packages that aren't Flarum extensions. For example, you need the guzzle library to use the [Mailgun mail driver](mail.md). In these cases, the instructions for the extension/feature in question should explain which version string to use. + +## How to install Composer? + +As with any other software, Composer must first be [installed](https://getcomposer.org/download/) on the server where Flarum is running. There are several options depending on the type of web hosting you have. + +### Dedicated Web Server + +In this case you can install composer as recommended in the Composer [guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### Managed / Shared hosting + +If Composer is not preinstalled (you can check this by running `composer --version`), you can use a [manual installation](https://getcomposer.org/composer-stable.phar). Just upload the composer.phar to your folder and run `/path/to/your/php7 composer.phar COMMAND` for any command documented as `composer COMMAND`. + +:::danger + +Some articles on the internet will mention that you can use tools like a PHP shell. If you are not sure what you are doing or what they are talking about - be careful! An unprotected web shell is **extremely** dangerous. + +::: + +## How do I use Composer? + +You'll need to use Composer over the **C**ommand-**l**ine **i**nterface (CLI). Be sure you can access your server over **S**ecure **Sh**ell (SSH). + +Once you have Composer installed, you should be able to run Composer commands in your SSH terminal via `composer COMMAND`. + +:::info Optimizations + +After most commands, you'll want to run `composer dump-autoload -a`. Essentially, this caches PHP files so they run faster. + +::: diff --git a/versioned_docs/version-1.x/config.md b/versioned_docs/version-1.x/config.md new file mode 100644 index 000000000..2b23101e9 --- /dev/null +++ b/versioned_docs/version-1.x/config.md @@ -0,0 +1,36 @@ +# Configuration File + +There is only one place where Flarum configuration cannot be modified through the Flarum admin dashboard (excluding the database), and that is the `config.php` file located in the root of your Flarum installation. + +This file, though small, contains details that are crucial for your Flarum installation to work. + +If the file exists, it tells Flarum that it has already been installed. +It also provides Flarum with database info and more. + +Here's a quick overview of what everything means with an example file: + +```php + false, // enables or disables debug mode, used to troubleshoot issues + 'offline' => false, // enables or disables site maintenance mode. This makes your site inaccessible to all users (including admins). + 'database' => + array ( + 'driver' => 'mysql', // the database driver, i.e. MySQL, MariaDB... + 'host' => 'localhost', // the host of the connection, localhost in most cases unless using an external service + 'database' => 'flarum', // the name of the database in the instance + 'username' => 'root', // database username + 'password' => '', // database password + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // the prefix for the tables, useful if you are sharing the same database with another service + 'port' => '3306', // the port of the connection, defaults to 3306 with MySQL + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // the URL installation, you will want to change this if you change domains + 'paths' => + array ( + 'api' => 'api', // /api goes to the API + 'admin' => 'admin', // /admin goes to the admin + ), +); +``` diff --git a/versioned_docs/version-1.x/console.md b/versioned_docs/version-1.x/console.md new file mode 100644 index 000000000..92d4fcf45 --- /dev/null +++ b/versioned_docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Console + +In addition to the admin dashboard, Flarum provides several console commands to help manage your forum over the terminal. + +Using the console: + +1. `ssh` into the server where your flarum installation is hosted +2. `cd` to the folder that contains the file `flarum` +3. Run the command via `php flarum [command]` + +## Default Commands + +### list + +Lists all available management commands, as well as instructions for using management commands + +### help + +`php flarum help [command_name]` + +Displays help output for a given command. + +You can also output the help in other formats by using the --format option: + +`php flarum help --format=xml list` + +To display the list of available commands, please use the list command. + +### info + +`php flarum info` + +Get information about Flarum's core and installed extensions. This is very useful for debugging issues, and should be shared when requesting support. + +### cache:clear + +`php flarum cache:clear` + +Clears the backend flarum cache, including generated js/css, text formatter cache, and cached translations. This should be run after installing or removing extensions, and running this should be the first step when issues occur. + +### assets:publish + +`php flarum assets:publish` + +Publish assets from core and extensions (e.g. compiled JS/CSS, bootstrap icons, logos, etc). This is useful if your assets have become corrupted, or if you have switched [filesystem drivers](extend/filesystem.md) for the `flarum-assets` disk. + +### migrate + +`php flarum migrate` + +Runs all outstanding migrations. This should be used when an extension that modifies the database is added or updated. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Reset all migrations for an extension. This is mostly used by extension developers, but on occasion, you might need to run this if you are removing an extension, and want to clear all of its data from the database. Please note that the extension in question must currently be installed (but not necessarily enabled) for this to work. + +### schedule:run + +`php flarum schedule:run` + +Many extensions use scheduled jobs to run tasks on a regular interval. This could include database cleanups, posting scheduled drafts, generating sitemaps, etc. If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +This command should generally not be run manually. + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +This command returns a list of scheduled commands (see `schedule:run` for more information). This is useful for confirming that commands provided by your extensions are registered properly. This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/versioned_docs/version-1.x/contributing-docs-translations.md b/versioned_docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..c30e96dda --- /dev/null +++ b/versioned_docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Docs and Translation + +## Add Documentation + +Adding documentation can help countless future Flarum users. A few ideas of what to work on: + +- User guides to help Flarum end users with some advanced Flarum features. +- More [frequently asked questions](faq.md). +- Expanded [troubleshooting](troubleshoot.md) steps. +- Step-by-step tutorials for Flarum development or installation. +- [Technical reference guides](extend/README.md) for extension developers. +- Improving literally anything else you think we should elaborate on or explain better. + +A good way to find topics to write about is to look for common questions in the [support tag](https://discuss.flarum.org/t/support) of our community. + +## Translate Flarum + +We want Flarum to be accessible to everyone, regardless of language! By contributing translations, you make it possible for many more people to enjoy Flarum. Best of all, we use user-friendly GUIs for translations, so no technical skills are necessary to help! + +Translations for Flarum core, bundled extensions, and community extensions are managed through [Weblate](https://weblate.rob006.net/projects/flarum/). + +Translations for this documentation are managed through [Crowdin](https://crowdin.com/project/flarum-docs). + +The Flarum Foundation has created the "flarum-lang" organization to support translators and ensure continuous availability of language packs. You can learn more about this by [visiting the GitHub repository](https://github.com/flarum-lang/about). + +If you want to support an existing language pack, start a new translation, or you run into issues using weblate or crowdin, it's best to [get in touch with the `flarum-lang` team](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/versioned_docs/version-1.x/contributing.md b/versioned_docs/version-1.x/contributing.md new file mode 100644 index 000000000..4fc952fd9 --- /dev/null +++ b/versioned_docs/version-1.x/contributing.md @@ -0,0 +1,171 @@ +# Help Build Flarum + +Interested in contributing to Flarum development? That's great! From [opening a bug report](bugs.md) to creating a pull request: every single one is appreciated and welcome. Flarum wouldn't be possible without our community contributions. + +Before contributing, please read the [code of conduct](code-of-conduct.md). + +This document is a guide for developers who want to contribute code to Flarum. If you're just getting started, we recommend that you read the [Getting Started](/extend/start.md) documentation in the Extension docs to understand a bit more about how Flarum works. + +## Why Contribute to Flarum? + +⚡ **Have Real Impact.** There are thousands of Flarum instances, with millions of aggregate end users. By contributing to Flarum, your code will have a positive impact on all of them. + +🔮 **Shape the Future of Flarum.** We have a long backlog, and limited time. If you're willing to champion a feature or change, it's much more likely to happen, and you'll be able to enact your vision for it. Plus, our roadmap and milestones are set by our [core development team](https://flarum.org/team), and all of us started as contributors. The best road to influence is contributing. + +🧑💻 **Become a Better Engineer.** Our codebase is modern, and we heavily value good engineering and clean code. There's also a lot of interesting, challenging problems to solve regarding design, infrastructure, performance, and extensibility. Especially if you're a student or early in your career, working on Flarum is a great opportunity to build development skills. + +🎠 **It's Fun!** We really enjoy working on Flarum: there's a lot of interesting challenges and fun features to build. We also have an active community on [our forums](https://discuss.flarum.org) and [Discord server](https://flarum.org/chat). + +## What to Work On + +Check out our upcoming [Milestones](https://github.com/flarum/core/milestones) for an overview of what needs to be done. See the [Good first issue](https://github.com/flarum/core/labels/Good%20first%20issue) label for a list of issues that should be relatively easy to get started with. If there's anything you're unsure of, don't hesitate to ask! All of us were just starting out once. + +If you're planning to go ahead and work on something, please comment on the relevant issue or create a new one first. This way we can ensure that your precious work is not in vain. + +Since Flarum is so extension-driven, we highly recommend [our extension docs](extend/README.md) as a reference when working on core, as well as for bundled extensions. You should start with [the introduction](extend/README.md) for a better understanding of our extension philosophy. + +## Development Setup + +### Setting Up a Local Codebase + +[flarum/flarum](https://github.com/flarum/flarum) is a "skeleton" application which uses Composer to download the core package and a bunch of extensions. Source code for Flarum core, extensions, and all packages used by the aforementioned is located in the Flarum monorepo [flarum/framework](https://github.com/flarum/framework). In order to contribute to these, you'll need to fork and clone the monorepo repository locally, and then add it to your dev environment as a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com/Hello!
+ } +} +``` + +### Setting Page as Homepage + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. +To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Page Titles + +Often, you'll want some custom text to appear in the browser tab's title for your page. +For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. +It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. +To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. +These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). +Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. +For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/versioned_docs/version-1.x/extend/frontend.md b/versioned_docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..ddd7385e0 --- /dev/null +++ b/versioned_docs/version-1.x/extend/frontend.md @@ -0,0 +1,431 @@ +# Frontend Development + +This page describes how to make changes to Flarum's user interface. How to add buttons, marquees, and blinking text. 🤩 + +[Remember](/extend/start.md#architecture), Flarum's frontend is a **single-page JavaScript application**. There's no Twig, Blade, or any other kind of PHP template to speak of. The few templates that are present in the backend are only used to render search-engine-optimized content. All changes to the UI need to be made via JavaScript. + +Flarum has two separate frontend applications: + +* `forum`, the public side of your forum where users create discussions and posts. +* `admin`, the private side of your forum where, as an administrator of your forum, you configure your Flarum installation. + +They share the same foundational code, so once you know how to extend one, you know how to extend both. + +:::tip Typings! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Transpilation and File Structure + +This portion of the guide will explain the necessary file setup for extensions. Once again, we highly recommend using the [Flarum CLI](https://github.com/flarum/cli) to set up the file structure for you. That being said, you should still read this to understand what's going on beneath the surface. + +Before we can write any JavaScript, we need to set up a **transpiler**. This allows us to use [TypeScript](https://www.typescriptlang.org/) and its magic in Flarum core and extensions. + +In order to do this transpilation, you need to be working in a capable environment. No, not the home/office kind of environment – you can work in the bathroom for all I care! I'm talking about the tools that are installed on your system. You'll need: + +* Node.js and npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +This can be tricky because everyone's system is different. From the OS you're using, to the program versions you have installed, to the user access permissions – I get chills just thinking about it! If you run into trouble, ~~tell him I said hi~~ use [Google](https://google.com) to see if someone has encountered the same error as you and found a solution. If not, ask for help from the [Flarum Community](https://discuss.flarum.org) or on the [Discord chat](https://flarum.org/discord/). + +It's time to set up our little JavaScript transpilation project. Create a new folder in your extension called `js`, then pop in a couple of new files. A typical extension will have the following frontend structure: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +This is a standard JS [package-description file](https://docs.npmjs.com/files/package.json), used by npm and Yarn (Javascript package managers). You can use it to add commands, js dependencies, and package metadata. We're not actually publishing a npm package: this is simply used to collect dependencies. + +Please note that we do not need to include `flarum/core` or any flarum extensions as dependencies: they will be automatically packaged when Flarum compiles the frontends for all extensions. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) is the system that actually compiles and bundles all the javascript (and its dependencies) for our extension. +To work properly, our extensions should use the [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (shown in the above example). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual +source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. +If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. +Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Importing + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. +Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Transpilation + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Asset Registration + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/versioned_docs/version-1.x/extend/search.md b/versioned_docs/version-1.x/extend/search.md new file mode 100644 index 000000000..6deab781b --- /dev/null +++ b/versioned_docs/version-1.x/extend/search.md @@ -0,0 +1,213 @@ +# Searching and Filtering + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). +Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. +We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. +For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. +After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. +This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. +It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the +query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. +This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. +For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. +See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. +You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/versioned_docs/version-1.x/extend/service-provider.md b/versioned_docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..6640bac28 --- /dev/null +++ b/versioned_docs/version-1.x/extend/service-provider.md @@ -0,0 +1,68 @@ +# Service Provider + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. +[Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. +The most common use case for service providers is to create, modify, or replace container bindings. +That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/versioned_docs/version-1.x/extend/settings.md b/versioned_docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..5e0f1b492 --- /dev/null +++ b/versioned_docs/version-1.x/extend/settings.md @@ -0,0 +1,93 @@ +# Settings + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. +Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. +Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. +However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/versioned_docs/version-1.x/extend/slugging.md b/versioned_docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/versioned_docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/versioned_docs/version-1.x/extend/start.md b/versioned_docs/version-1.x/extend/start.md new file mode 100644 index 000000000..b73125a7c --- /dev/null +++ b/versioned_docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Getting Started + +Want to build a Flarum extension? You've come to the right place! This document will take you through some essential concepts, after which you'll build your first Flarum extension from scratch. + +## Architecture + +In order to understand how to extend Flarum, first we need to understand a bit about how Flarum is built. + +Be aware that Flarum uses some _modern_ languages and tools. If you've only ever built WordPress plugins before, you might feel a bit out of your depth! That's OK — this is a great time to learn cool new things and extend your skillset. However, we would advise that you become somewhat familiar with the technologies described below before proceeding. + +Flarum is made up of three layers: + +* First, there is the **backend**. This is written in [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), and makes use of a wide array of [Laravel](https://laravel.com/) components and other packages via [Composer](https://getcomposer.org/). You'll also want to familiarize yourself with the concept of [Dependency Injection](https://laravel.com/docs/8.x/container), which is used throughout our backend. + +* Second, the backend exposes a **public API** which allows frontend clients to interface with your forum's data. This is built according to the [JSON:API specification](https://jsonapi.org/). + +* Finally, there is the default web interface which we call the **frontend**. This is a [single-page application](https://en.wikipedia.org/wiki/Single-page_application) which consumes the API. It's built with a simple React-like framework called [Mithril.js](https://mithril.js.org). + +Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the **backend**, expose that data in the **public API**, and then display it and allow users to edit it on the **frontend**. + +So... how do we extend these layers? + +## Extenders + +In order to extend Flarum, we will be using a concept called **extenders**. Extenders are *declarative* objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created). + +Every extender is different. However, they will always look somewhat similar to this: + +```php +// Register a JavaScript and a CSS file to be delivered with the forum frontend +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls. + +To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). _Everything_ you do in your extension should be done via extenders, because they are a **guarantee** we are giving to you that a future minor release of Flarum won't break your extension. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hello World + +Want to see an extender in action? The `extend.php` file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Now pay your forum a visit for a pleasant (albeit extremely obtrusive) greeting. 👋 + +For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the `extend.php` file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension! + +## Extension Packaging + +[Composer](https://getcomposer.org) is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly. + +As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice! + +During development, you can work on your extensions locally and set up a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path) to install your local copy. Create a new `packages` folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here: + +```bash +composer config repositories.0 path "packages/*" +``` + +Now let's start building our first extension. Make a new folder inside `packages` for your extension called `hello-world`. We'll put two files in it: `extend.php` and `composer.json`. These files serve as the heart and soul of the extension. + +### extend.php + +The `extend.php` file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the `Frontend` extender that you had earlier. + +### composer.json + +We need to tell Composer a bit about our package, and we can do this by creating a `composer.json` file: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": "^1.0.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** is the name of the Composer package in the format `vendor/package`. + * You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using `acme` as your vendor name. + * You should prefix the `package` part with `flarum-` to indicate that it’s a package specifically intended for use with Flarum. + +* **description** is a short one-sentence description of what the extension does. + +* **type** MUST be set to `flarum-extension`. This ensures that when someone "requires" your extension, it will be identified as such. + +* **require** contains a list of your extension's own dependencies. + * You'll want to specify the version of Flarum that your extension is compatible with here. + * This is also the place to list other Composer libraries your code needs to work. + +* **autoload** tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase. + +* **extra.flarum-extension** contains some Flarum-specific information, like your extension's display name and how its icon should look. + * **title** is the display name of your extension. + * **icon** is an object which defines your extension's icon. The **name** property is a [Font Awesome icon class name](https://fontawesome.com/icons). All other properties are used as the `style` attribute for your extension's icon. + +See [the composer.json schema](https://getcomposer.org/doc/04-schema.md) documentation for information about other properties you can add to `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Use the CLI to automatically create your extension's scaffolding: +```bash +$ flarum-cli init +``` + +::: + +### Installing Your Extension + +The final thing we need to do to get up and running is to install your extension. Navigate to the root directory of your Flarum install and run the following command: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Once that's done, go ahead and fire 'er up on your forum's Administration page, then navigate back to your forum. + +*whizzing, whirring, metal clunking* + +Woop! Hello to you too, extension! + +We're making good progress. We've learned how to set up our extension and use extenders, which opens up a lot of doors. Read on to learn how to extend Flarum's frontend. diff --git a/versioned_docs/version-1.x/extend/static-code-analysis.md b/versioned_docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/versioned_docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/versioned_docs/version-1.x/extend/testing.md b/versioned_docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..6a9b32402 --- /dev/null +++ b/versioned_docs/version-1.x/extend/testing.md @@ -0,0 +1,570 @@ +# Testing + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. +Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. +It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + +something
Hello World!
; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return{this.counter}
; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +{this.attrs.counter}
; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +Counter: {app.counter.getCount()}
+Hello World!{this.showContent ? ' Extra Content!' : ''}
+Hello World!
Hello World
" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. +The name of the invalid field is returned as the `pointer` value. +There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/versioned_docs/version-1.x/scheduler.md b/versioned_docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/versioned_docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/versioned_docs/version-1.x/themes.md b/versioned_docs/version-1.x/themes.md new file mode 100644 index 000000000..ba0e46541 --- /dev/null +++ b/versioned_docs/version-1.x/themes.md @@ -0,0 +1,33 @@ +# Theming + +While we've worked hard to make Flarum as beautiful as we can, each community will probably want to make some tweaks/modifications to fit their desired style. + +## Admin Dashboard + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Here, you can: + +- Select theme colors +- Toggle dark mode and a colored header +- Upload a logo and favicon (icon shown in browser tabs) +- Add HTML for custom headers and footers +- Add [custom LESS/CSS](#css-theming) to change how elements are displayed + +## CSS Theming + +CSS is a style sheet language that tells browsers how to display elements of a webpage. +It allows us to modify everything from colors to fonts to element size and positioning to animations. +Adding custom CSS can be a great way to modify your Flarum installation to match a theme. + +A CSS tutorial is beyond the scope of this documentation, but there are plenty of great online resources to learn the basics of CSS. + +:::tip + +Flarum actually uses LESS, which makes it easier to write CSS by allowing for variables, conditionals, and functions. + +::: + +## Extensions + +Flarum's flexible [extension system](extensions.md) allows you to add, remove, or modify practically any part of Flarum. +If you want to make substantial theming modifications beyond changing colors/sizes/styles, a custom extension is definitely the way to go. +To learn how to make an extension, check out our [extension documentation](extend/README.md)! diff --git a/versioned_docs/version-1.x/troubleshoot.md b/versioned_docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..7bae80216 --- /dev/null +++ b/versioned_docs/version-1.x/troubleshoot.md @@ -0,0 +1,57 @@ +# Troubleshooting + +If Flarum isn't installing or working as expected, the first thing you should do is *check again* whether your environment meets the [system requirements](install.md#server-requirements). If you're missing something that Flarum needs to run, you'll need to remedy that first. + +Next, you should take a few minutes to search the [Support forum](https://discuss.flarum.org/t/support) and the [issue tracker](https://github.com/flarum/core/issues). It's possible that someone has already reported the problem, and a fix is either available or on the way. If you've searched thoroughly and can't find any information about the problem, it's time to start troubleshooting. + +## Step 0: Activate debug mode + +:::danger Skip on Production + +These debugging tools are very useful, but can expose information that shouldn't be public. +These are fine if you're on a staging or development environment, but if you don't know what you're doing, skip this step when on a production environment. + +::: + +Before you proceed, you should enable Flarum's debugging tools. Simply open up **config.php** with a text editor, change the `debug` value to `true`, and save the file. This will cause Flarum to display detailed error messages, giving you an insight into what's going wrong. + +If you've been seeing blank pages and the above change doesn't help, try setting `display_errors` to `On` in your **php.ini** configuration file. + +## Step 1: Common Fixes + +A lot of issues can be fixed with the following: + +* Clear your browser cache +* Clear the backend cache with [`php flarum cache:clear`](console.md). +* Make sure your database is updated with [`php flarum migrate`](console.md). +* Ensure that the [email configuration](mail.md) in your admin dashboard is correct: invalid email config will cause errors when registering, resetting a password, changing emails, and sending notifications. +* Check that your `config.php` is correct. For instance, make sure that the right `url` is being used (`https` vs `http` and case sensitivity matter here!). +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +You'll also want to take a look at the output of [`php flarum info`](console.md) to ensure that nothing major is out of place. + +## Step 2: Reproduce the issue + +Try to make the problem happen again. Pay careful attention to what you're doing when it occurs. Does it happen every time, or only now and then? Try changing a setting that you think might affect the problem, or the order in which you're doing things. Does it happen under some conditions, but not others? + +If you've recently added or updated an extension, you should disable it temporarily to see if that makes the problem go away. Make sure all of your extensions were meant to be used with the version of Flarum you're running. Outdated extensions can cause a variety of issues. + +Somewhere along the way you may get an idea about what's causing your issue, and figure out a way to fix it. But even if that doesn't happen, you will probably run across a few valuable clues that will help us figure out what's going on, once you've filed your bug report. + +## Step 3: Collect information + +If it looks like you're going to need help solving the problem, it's time to get serious about collecting data. Look for error messages or other information about the problem in the following places: + +* Displayed on the actual page +* Displayed in the browser console (Chrome: More tools -> Developer Tools -> Console) +* Recorded in the server's error log (e.g. `/var/log/nginx/error.log`) +* Recorded in PHP-FPM's error log (e.g. `/var/log/php7.x-fpm.log`) +* Recorded by Flarum (`storage/logs`) + +Copy any messages to a text file and jot down a few notes about *when* the error occurred, *what* you were doing at the time, and so on. Be sure to include any insights you may have gleaned about the conditions under which the issue does and doesn't occur. Add as much information as possible about your server environment: OS version, web server version, PHP version and handler, et cetera. + +## Step 4: Prepare a report + +Once you have gathered all the information you can about the problem, you're ready to file a bug report. Please follow the instructions on [Reporting Bugs](bugs.md). + +If you discover something new about the issue after filing your report, please add that information at the bottom of your original post. It's a good idea to file a report even if you have solved the problem on your own, since other users may also benefit from your solution. If you've found a temporary workaround for the problem, be sure to mention that as well. \ No newline at end of file diff --git a/versioned_docs/version-1.x/update.md b/versioned_docs/version-1.x/update.md new file mode 100644 index 000000000..21b090eb2 --- /dev/null +++ b/versioned_docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Updating + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +To update Flarum, you'll need to use [Composer](https://getcomposer.org). If you're not familiar with it (although you should be, because you need it to install Flarum), read [our guide](composer.md) for information on what it is and how to set it up. + +If updating across major versions (e.g. <=0.1.0 to 1.x.x, 1.x.x to 2.x.x, ...), make sure to read the appropriate "major version update guide" before running the general upgrade steps. + +## General Steps + +**Step 1:** Make sure all your extensions have versions compatible with the Flarum version you're trying to install. This is only needed across major versions (e.g. you probably don't need to check this if upgrading from v1.0.0 to v1.1.0, assuming your extensions follow recommended versioning). You can check this by looking at the extension's [Discuss thread](https://discuss.flarum.org/t/extensions), searching for it on [Packagist](http://packagist.org/), or checking databases like [Extiverse](https://extiverse.com). You'll need to remove (not just disable) any incompatible extensions before updating. Please be patient with extension developers! + +**Step 2:** Take a look at your `composer.json` file. Unless you have a reason to require specific versions of extensions or libraries, you should set the version string of everything except `flarum/core` to `*` (including `flarum/tags`, `flarum/mentions`, and other bundled extensions). Make sure `flarum/core` is NOT set to `*`. If you're targeting a specific version of Flarum, set `flarum/core` to that (e.g. `"flarum/core": "v0.1.0-beta.16`). If you just want the most recent version, use `"flarum/core": "^1.0"`. + +**Step 3:** If your local install uses [local extenders](extenders.md), make sure they are up to date with changes in Flarum. + +**Step 4:** We recommend disabling third-party extensions in the admin dashboard before updating. This isn't strictly required, but will make debugging easier if you run into issues. + +**Step 5:** Make sure your PHP version is supported by the version of Flarum you are trying to upgrade to, and that you are using Composer 2 (`composer --version)`. + +**Step 6:** Finally, to update, run: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Step 7:** If applicable, restart your PHP process and opcache. + +## Major Version Update Guides + +### Updating from Beta (<=0.1.0) to Stable v1 (^1.0.0) + +1. Do steps 1-5 above. +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## Troubleshooting Issues + +There are 2 main places where you might run into errors when updating Flarum: while running the update command itself, or when accessing the forum after updating. + +### Errors While Updating + +Here we'll go through several common types of issues while trying to update Flarum. + +--- + +If the output is short and contains: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +If you are unable to access your forum after updating, follow our [troubleshooting instructions](troubleshoot.md). diff --git a/versioned_sidebars/version-1.x-sidebars.json b/versioned_sidebars/version-1.x-sidebars.json new file mode 100644 index 000000000..c8edad68f --- /dev/null +++ b/versioned_sidebars/version-1.x-sidebars.json @@ -0,0 +1,155 @@ +{ + "guideSidebar": [ + { + "type": "category", + "label": "Introduction", + "collapsible": false, + "items": [ + "README", + "code-of-conduct", + "releases", + "bugs", + "faq" + ] + }, + { + "type": "category", + "label": "Contribute", + "collapsible": false, + "items": [ + "contributing", + "contributing-docs-translations", + { + "type": "link", + "label": "Other Ways to Help", + "href": "/#help-the-flarum-project" + } + ] + }, + { + "type": "category", + "label": "Setting Up", + "collapsible": false, + "items": [ + "composer", + "install", + "update", + "troubleshoot" + ] + }, + { + "type": "category", + "label": "Management", + "collapsible": false, + "items": [ + "admin", + "config", + "extensions", + "languages", + "themes", + "mail", + "scheduler", + "console" + ] + }, + { + "type": "category", + "label": "Advanced", + "collapsible": false, + "items": [ + "rest-api", + "extenders" + ] + } + ], + "extendSidebar": [ + { + "type": "category", + "label": "Main Concepts", + "collapsible": false, + "items": [ + "extend/README", + "extend/start", + "extend/frontend", + "extend/routes", + "extend/models", + "extend/api", + "extend/distribution", + "extend/cli" + ] + }, + { + "type": "category", + "label": "Reference Guides", + "collapsible": false, + "items": [ + "extend/admin", + "extend/backend-events", + "extend/authorization", + "extend/frontend-pages", + "extend/interactive-components", + "extend/i18n", + "extend/language-packs", + "extend/forms", + "extend/permissions", + "extend/settings", + "extend/static-code-analysis", + "extend/testing", + "extend/theme", + "extend/views", + "extend/github-actions" + ] + }, + { + "type": "category", + "label": "Advanced Guides", + "collapsible": false, + "items": [ + "extend/api-throttling", + "extend/assets", + "extend/console", + "extend/extending-extensions", + "extend/extensibility", + "extend/filesystem", + "extend/formatting", + "extend/mail", + "extend/middleware", + "extend/model-visibility", + "extend/slugging", + "extend/notifications", + "extend/post-types", + "extend/search", + "extend/service-provider" + ] + }, + { + "type": "category", + "label": "Update Guides", + "collapsible": false, + "items": [ + "extend/update-1_x", + "extend/update-1_0", + "extend/update-b16", + "extend/update-b15", + "extend/update-b14", + "extend/update-b13", + "extend/update-b12", + "extend/update-b10", + "extend/update-b8" + ] + } + ], + "internalSidebar": [ + { + "type": "category", + "label": "Internal Docs", + "collapsible": false, + "items": [ + "internal/README", + "internal/merging-policy", + "internal/bundled-extensions-policy", + "internal/extension-manager" + ] + } + ] +} diff --git a/versions.json b/versions.json new file mode 100644 index 000000000..056f6d568 --- /dev/null +++ b/versions.json @@ -0,0 +1,3 @@ +[ + "1.x" +]