فصل سوم: جادوی محلی‌سازی: آوردن طعم پارسی و تقویم جلالی به Nextcloud

هدف فصل: ساخت یک تجربه بومی و جذاب

تصور کنید Nextcloud را به یک فضای ابری کاملاً پارسی تبدیل کنید، جایی که هر منو به زبان فارسی سخن می‌گوید و تاریخ‌ها با تقویم جلالی، قلب فرهنگ ایران، نمایش داده می‌شوند! در این فصل، با فارسی‌سازی رابط کاربری و ادغام تقویم جلالی در هسته و اپلیکیشن‌های Nextcloud ۳۲.۰.۰، شما را به یک سفر برنامه‌نویسی هیجان‌انگیز می‌بریم. از ترجمه‌های روان تا نمایش تاریخ‌های شمسی، این فصل پروژه شما را به یک اثر بومی و کاربرپسند تبدیل می‌کند.


۳.۱ فارسی‌سازی: صحبت به زبان کاربر

برای اینکه Nextcloud برای کاربران پارسی‌زبان آشنا و دلنشین باشد، باید رابط کاربری را به فارسی ترجمه کنیم و آن را با جهت‌گیری راست‌به‌چپ (RTL) و فونت‌های زیبای پارسی هماهنگ کنیم.

۳.۱.۱ افزودن ترجمه‌های پارسی: صدای پروژه شما

ترجمه‌ها به Nextcloud اجازه می‌دهند که به زبان فارسی با کاربران صحبت کند. ما از سیستم l10n استفاده می‌کنیم تا رشته‌های متنی را جایگزین کنیم.

  1. ایجاد فایل ترجمه: فایل: apps/myapp/l10n/fa.json
   {
       "translations": {
           "Files": "فایل‌ها",
           "Settings": "تنظیمات",
           "Calendar": "تقویم",
           "Save": "ذخیره",
           "Share": "اشتراک‌گذاری"
       },
       "pluralForm": "nplurals=2; plural=(n != 1);"
   }
  1. ثبت ترجمه در اپلیکیشن: فایل: apps/myapp/appinfo/app.php
   <?php
   namespace OCA\MyApp;

   use OCP\AppFramework\App;

   class MyApp extends App {
       public function __construct(array $urlParams = []) {
           parent::__construct('myapp', $urlParams);
           \OC::$server->getL10N('myapp')->load();
       }
   }
  1. استفاده در رابط کاربری (Vue): فایل: apps/myapp/src/components/MyComponent.vue
   <template>
       <div>{{ t('Files') }}</div>
   </template>
   <script>
   import { getTranslator } from '@nextcloud/l10n';
   export default {
       methods: {
           t(key) {
               return getTranslator('myapp').t(key);
           }
       }
   }
   </script>

تست:

   console.log(getTranslator('myapp').t('Files')); // فایل‌ها

۳.۱.۲ پشتیبانی از RTL: طراحی برای خوانندگان پارسی

جهت راست‌به‌چپ و فونت‌های پارسی، تجربه کاربری را برای ایرانیان بهینه می‌کند.

  1. ایجاد استایل RTL: فایل: apps/myapp/css/rtl.css
   [dir="rtl"] {
       direction: rtl;
       text-align: right;
       unicode-bidi: embed;
   }
   .myapp-container {
       margin-inline-start: 1rem;
       padding: 1rem;
   }
   @font-face {
       font-family: 'Vazir';
       src: url('https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.woff2') format('woff2');
       font-display: swap;
   }
   body {
       font-family: 'Vazir', sans-serif;
   }
  1. فعال‌سازی RTL: فایل: apps/myapp/appinfo/app.php
   \OCP\Util::addStyle('myapp', 'rtl');
   \OCP\Util::addHeader('html', ['dir' => 'rtl', 'lang' => 'fa']);
  1. اعمال فونت در سرور: فایل: themes/persian-theme/core/css/server.css
   body {
       font-family: 'Vazir', sans-serif;
   }

تست: به http://localhost:8080 بروید و مطمئن شوید متن‌ها راست‌چین و با فونت Vazir هستند.


۳.۲ ادغام تقویم جلالی: قلب پارسی پروژه

تقویم جلالی، که بر اساس چرخه خورشیدی کار می‌کند، برای کاربران ایرانی ضروری است.

۳.۲.۱ نصب کتابخانه‌های جلالی

npm install date-fns-jalali
composer require morilog/jalali

۳.۲.۲ کلاس تبدیل جلالی

فایل: apps/myapp/lib/Calendar/JalaliConverter.php

<?php
namespace OCA\MyApp\Calendar;
use Morilog\Jalali\Jalalian;

class JalaliConverter {
    public static function toJalali(\DateTime $date): array {
        $jalali = Jalalian::fromDateTime($date);
        return [
            'year' => $jalali->getYear(),
            'month' => $jalali->getMonth(),
            'day' => $jalali->getDay()
        ];
    }

    public static function toGregorian(int $year, int $month, int $day): \DateTime {
        return Jalalian::fromFormat('Y/m/d', sprintf('%d/%d/%d', $year, $month, $day))
            ->toCarbon()->toDateTime();
    }

    public static function formatJalali(\DateTime $date, string $format): string {
        return Jalalian::fromDateTime($date)->format($format);
    }
}

۳.۲.۳ ادغام در هسته

فایل: apps/myapp/appinfo/app.php

$container->getServer()->get(IEventDispatcher::class)->addListener(
    'OCP\Template::render',
    function ($event) {
        $params = $event->getParameters();
        if (isset($params['date']) && $params['date'] instanceof \DateTime) {
            $params['date'] = \OCA\MyApp\Calendar\JalaliConverter::formatJalali(
                $params['date'], 'Y/m/d'
            );
            $event->setParameters($params);
        }
    }
);

۳.۲.۴ جلالی در JavaScript

فایل: apps/myapp/js/jalali.js

import { format } from 'date-fns-jalali';

if (!OC.Util) OC.Util = {};
OC.Util.formatJalaliDate = (date, pattern = 'yyyy/MM/dd') => {
    try {
        return format(new Date(date), pattern, { calendar: 'jalali' });
    } catch (e) {
        console.error('خطا در فرمت تاریخ جلالی:', e);
        return date.toLocaleDateString('fa-IR');
    }
};

بارگذاری:

\OCP\Util::addScript('myapp', 'jalali');

۳.۲.۵ ادغام با Datepicker

نصب:

npm install flatpickr flatpickr-jalali

فایل: apps/myapp/src/components/JalaliPicker.vue

<template>
    <input ref="picker" type="text" class="jalali-picker" />
</template>
<script>
import Flatpickr from 'flatpickr';
import 'flatpickr-jalali';
import 'flatpickr/dist/flatpickr.min.css';

export default {
    name: 'JalaliPicker',
    mounted() {
        Flatpickr(this.$refs.picker, {
            calendar: 'jalali',
            locale: 'fa',
            dateFormat: 'Y/m/d',
            onChange: (selectedDates) => {
                this.$emit('input', OC.Util.formatJalaliDate(selectedDates[0]));
            }
        });
    }
}
</script>
<style>
.jalali-picker {
    font-family: 'Vazir', sans-serif;
    direction: rtl;
}
</style>

۳.۳ تست: اطمینان از جادوی پارسی

  1. فعال‌سازی اپلیکیشن:
   php occ app:enable myapp
  1. تست API: فایل: apps/myapp/lib/Controller/TestController.php
   <?php
   namespace OCA\MyApp\Controller;

   use OCP\AppFramework\Controller;
   use OCP\AppFramework\Http\JSONResponse;
   use OCP\IRequest;
   use OCA\MyApp\Calendar\JalaliConverter;

   class TestController extends Controller {
       public function __construct($appName, IRequest $request) {
           parent::__construct($appName, $request);
       }

       /**
        * @NoAdminRequired
        * @NoCSRFRequired
        */
       public function index() {
           $date = new \DateTime('2025-03-21');
           return new JSONResponse([
               'jalali' => JalaliConverter::formatJalali($date, 'Y/m/d')
           ]);
       }
   }

مسیر: apps/myapp/appinfo/routes.php

   ['name' => 'test#index', 'url' => '/api/index', 'verb' => 'GET']

تست:

   curl http://localhost:8080/index.php/apps/myapp/api/index
  1. تست JavaScript:
   OC.Util.formatJalaliDate(new Date('2025-03-21')) // 1404/01/01
  1. تست UI:
  2. به http://localhost:8080 بروید.
  3. تاریخ‌ها و متن‌ها را بررسی کنید.

نکات حرفه‌ای

  • کشینگ: از Redis برای ذخیره تبدیل‌ها استفاده کنید.
  • دسترسی‌پذیری: با WAVE تست کنید.
  • مستندات: در README.fa.md بنویسید.