> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kombify.io/llms.txt
> Use this file to discover all available pages before exploring further.

# إعداد تطبيقات مدير كلمات المرور

> أنشئ حساب خزنتك، واحفظ أول كلمة مرور، ثم اربط تطبيقات Bitwarden على هاتفك ومتصفحك وحاسوبك بخزنتك الخاصة.

export const ClientSetupGuide = ({id, labels, locale = 'en', direction = 'ltr', meta = [], requirements = [], requirementsHelp, appsTitle = labels.appsTitle, vendor, apps = [], appsNote, stepsTitle = labels.stepsTitle, steps = [], help = [], helpTitle = labels.helpTitle, next = [], nextTitle = labels.nextTitle, attribution, sources}) => {
  const Anchor = 'a', Article = 'article', Details = 'details', Dialog = 'dialog', Figcaption = 'figcaption', Figure = 'figure', Footer = 'footer', Img = 'img', Summary = 'summary';
  const number = new Intl.NumberFormat(locale);
  const stepNumber = new Intl.NumberFormat(locale, {
    minimumIntegerDigits: 2
  });
  const message = (key, values = {}) => labels[key].replace(/\{(\w+)\}/g, (_, name) => String(values[name]));
  const count = steps.length;
  const last = count - 1;
  const storageKey = `kombify-client-guide:${id}:v1`;
  const rootRef = useRef(null);
  const zoomRef = useRef(null);
  const toastTimer = useRef(null);
  const focusTab = useRef(false);
  const [current, setCurrent] = useState(0);
  const [completed, setCompleted] = useState(() => steps.map(() => false));
  const [verified, setVerified] = useState(() => steps.map(step => (step.verify || []).map(() => false)));
  const [failed, setFailed] = useState({});
  const [zoom, setZoom] = useState(null);
  const [toast, setToast] = useState('');
  const isExternal = href => (/^https?:\/\//).test(href || '');
  const icon = name => {
    const paths = {
      apple: <path d="M16.7 1.8c0 2.1-1.7 4.4-3.7 4.2-.4-2.1 1.8-4.3 3.7-4.2ZM20.4 17.3c-.5 1.2-.8 1.7-1.5 2.7-1 1.5-2.4 3.3-4.2 3.3-1.6 0-2-1-4.1-.9-2.1 0-2.5 1-4.2.9-1.8-.1-3.1-1.7-4.1-3.2C-.5 15.9-.7 10.4 1 7.6c1.2-2 3.1-3.1 4.9-3.1 1.9 0 3.1 1 4.7 1 1.5 0 2.5-1 4.7-1 1.6 0 3.3.9 4.5 2.3-4 2.2-3.3 8 0 10.5Z" fill="currentColor" stroke="none" transform="translate(2 0) scale(.87)" />,
      android: <><path d="M5 12a7 7 0 0 1 14 0v6H5Zm2-6L5 3m12 3 2-3M2 12v5m20-5v5M8 18v4m8-4v4" /><path d="M8.5 9h.01M15.5 9h.01" /></>,
      browser: <><rect height="16" rx="2" width="20" x="2" y="4" /><path d="M2 9h20M6 6.5h.01M9 6.5h.01" /></>,
      desktop: <><rect height="14" rx="2" width="20" x="2" y="3" /><path d="M8 22h8M12 17v5" /></>,
      web: <><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /></>,
      server: <><rect height="7" rx="2" width="18" x="3" y="3" /><rect height="7" rx="2" width="18" x="3" y="14" /><path d="M7 6.5h.01M7 17.5h.01M16 6.5h2M16 17.5h2" /></>,
      phone: <><rect height="20" rx="3" width="12" x="6" y="2" /><path d="M10 5h4M11 19h2" /></>,
      steps: <><rect height="7" rx="1.5" width="7" x="3" y="3" /><rect height="7" rx="1.5" width="7" x="14" y="3" /><rect height="7" rx="1.5" width="7" x="3" y="14" /><rect height="7" rx="1.5" width="7" x="14" y="14" /></>,
      book: <path d="M12 5v15M3 4c4-1 6 0 9 1 3-1 5-2 9-1v15c-4-1-6 0-9 1-3-1-5-2-9-1Z" />,
      clock: <><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></>,
      print: <><path d="M6 8V3h12v5M6 17H3V8h18v9h-3M6 14h12v7H6Z" /><path d="M17 11h.01" /></>,
      check: <path d="m5 12 4 4L19 6" />,
      arrow: <path d="M5 12h14M13 6l6 6-6 6" />,
      back: <path d="m15 5-7 7 7 7" />,
      external: <><path d="M14 4h6v6m0-6L10 14" /><path d="M10 4H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-5" /></>,
      info: <><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 7h.01" /></>,
      ok: <><circle cx="12" cy="12" r="9" /><path d="m8 12 3 3 5-6" /></>,
      camera: <><path d="M3 7h4l2-3h6l2 3h4v13H3Z" /><circle cx="12" cy="13" r="4" /></>,
      zoom: <><circle cx="10.5" cy="10.5" r="6.5" /><path d="m16 16 5 5M7 10.5h7M10.5 7v7" /></>,
      shield: <><path d="M12 3 3 7v6c0 5 9 9 9 9s9-4 9-9V7Z" /><path d="m8 12 3 3 5-6" /></>,
      close: <path d="m6 6 12 12M6 18 18 6" />
    };
    return <svg aria-hidden="true" className="ico" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.7" viewBox="0 0 24 24">{paths[name] || paths.info}</svg>;
  };
  const safeHref = href => (/^(https:\/\/|\/|#)/).test(href || '') ? href : '#';
  const link = (href, children, className, key) => isExternal(href) ? <Anchor className={className || ''} href={safeHref(href)} key={key} rel="noopener noreferrer" target="_blank">{children} {icon('external')}<span className="sr-only">{labels.opensInNewTab}</span></Anchor> : <Anchor className={className || ''} href={safeHref(href)} key={key} onClick={(href || '').startsWith('#') ? () => {
    zoomRef.current?.close();
    reveal(href.slice(1));
  } : undefined}>{children}</Anchor>;
  const rich = text => {
    if (!text || !text.split) return text;
    return text.split(/(\[\[[^\]]+\]\]|\*\*[^*]+\*\*|\[[^\]]+\]\([^)\s]+\))/g).map((part, i) => {
      if ((/^\[\[[^\]]+\]\]$/).test(part)) return <span className="key" key={i}>{part.slice(2, -2)}</span>;
      if ((/^\*\*[^*]+\*\*$/).test(part)) return <strong key={i}>{part.slice(2, -2)}</strong>;
      const match = (/^\[([^\]]+)\]\(([^)\s]+)\)$/).exec(part);
      if (match) return link(match[2], match[1], undefined, i);
      return part;
    });
  };
  useEffect(() => {
    try {
      const saved = JSON.parse(localStorage.getItem(storageKey) || 'null');
      if (Array.isArray(saved?.completed) && saved.completed.length === count) setCompleted(saved.completed.map(Boolean));
      if (Array.isArray(saved?.verified) && saved.verified.length === count) setVerified(saved.verified.map((list, i) => (steps[i].verify || []).map((_, j) => Boolean(list?.[j]))));
    } catch (_) {}
    const root = rootRef.current;
    const timer = setTimeout(() => {
      if (!root) return;
      const broken = {};
      root.querySelectorAll('.screen-image > img').forEach(image => {
        if (image.complete && !image.naturalWidth) broken[image.getAttribute('src')] = true;
      });
      if (Object.keys(broken).length) setFailed(old => ({
        ...old,
        ...broken
      }));
    }, 7000);
    const openAll = () => root?.querySelectorAll('details').forEach(node => {
      node.open = true;
    });
    window.addEventListener('beforeprint', openAll);
    return () => {
      clearTimeout(timer);
      clearTimeout(toastTimer.current);
      window.removeEventListener('beforeprint', openAll);
    };
  }, []);
  useEffect(() => {
    if (!focusTab.current) return;
    focusTab.current = false;
    rootRef.current?.querySelector(`[id="${id}-tab-${current}"]`)?.focus();
  }, [current]);
  const persist = (nextCompleted, nextVerified) => {
    try {
      localStorage.setItem(storageKey, JSON.stringify({
        completed: nextCompleted,
        verified: nextVerified
      }));
    } catch (_) {}
  };
  const say = text => {
    setToast('');
    setTimeout(() => setToast(text), 60);
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(''), 3800);
  };
  const select = (index, focus) => {
    const target = Math.max(0, Math.min(last, index));
    setCurrent(target);
    focusTab.current = Boolean(focus);
  };
  const onNext = () => {
    const checks = verified[current] || [];
    if (checks.length && !checks.every(Boolean)) {
      say(labels.verifyRequired);
      rootRef.current?.querySelector(`[id="${id}-verify-${current}-${checks.indexOf(false)}"]`)?.focus();
      return;
    }
    const nextCompleted = completed.map((done, i) => i === current ? true : done);
    setCompleted(nextCompleted);
    persist(nextCompleted, verified);
    if (current < last) select(current + 1, true); else {
      const done = nextCompleted.filter(Boolean).length;
      say(done === count ? labels.allDone : message('remainingSteps', {
        done: number.format(done),
        count: number.format(count)
      }));
      rootRef.current?.querySelector(`[id="${id}-more"], [id="${id}-help"]`)?.scrollIntoView({
        block: 'start'
      });
    }
  };
  const onVerify = (stepIndex, checkIndex, value) => {
    const nextVerified = verified.map((list, i) => i === stepIndex ? list.map((v, j) => j === checkIndex ? value : v) : list);
    const nextCompleted = completed.map((done, i) => i === stepIndex && !value ? false : done);
    setVerified(nextVerified);
    setCompleted(nextCompleted);
    persist(nextCompleted, nextVerified);
  };
  const onReset = () => {
    const nextCompleted = steps.map(() => false);
    const nextVerified = steps.map(step => (step.verify || []).map(() => false));
    setCompleted(nextCompleted);
    setVerified(nextVerified);
    persist(nextCompleted, nextVerified);
    select(0);
    say(labels.progressReset);
  };
  const onTabKey = event => {
    const moves = {
      ArrowRight: c => (c + 1) % count,
      ArrowLeft: c => (c - 1 + count) % count,
      Home: () => 0,
      End: () => last
    };
    const move = moves[event.key];
    if (!move) return;
    event.preventDefault();
    focusTab.current = true;
    setCurrent(move);
  };
  const openZoom = shot => {
    setZoom(shot);
    const dialog = zoomRef.current;
    if (dialog && !dialog.open) dialog.showModal();
  };
  const closeOnBackdrop = event => {
    const dialog = event.currentTarget;
    if (event.target !== dialog) return;
    const rect = dialog.getBoundingClientRect();
    if (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom) dialog.close();
  };
  const reveal = targetId => {
    const node = rootRef.current?.querySelector(`[id="${targetId}"]`);
    const details = node && (node.tagName === 'DETAILS' ? node : node.querySelector('details'));
    if (details) details.open = true;
  };
  const renderShot = (shot, stepIndex) => {
    const unavailable = failed[shot.src];
    const label = shot.vendor ? labels.vendorScreenshotTag : labels.kombifyScreenshotTag;
    return <>
        <span className="screenshot-tag">{icon('camera')} {label}</span>
        <Figure className={`screen-figure${shot.frame === 'phone' ? ' phone' : ''}${unavailable ? ' image-unavailable' : ''}`}>
          <div className="screen-image">
            <Img alt={shot.alt} className={shot.srcDark ? 'only-light has-dark' : undefined} decoding="async" height={shot.height} loading={stepIndex === 0 ? 'eager' : 'lazy'} onError={() => setFailed(old => ({
      ...old,
      [shot.src]: true
    }))} referrerPolicy="no-referrer" src={shot.src} width={shot.width} />
            {shot.srcDark ? <Img alt={shot.alt} className="only-dark" decoding="async" height={shot.height} loading="lazy" onError={() => setFailed(old => ({
      ...old,
      [shot.src]: true
    }))} src={shot.srcDark} width={shot.width} /> : null}
            {(shot.vendor ? [] : shot.annotations || []).map((mark, i) => <span aria-hidden="true" className="annotation" data-n={mark.n ?? undefined} key={i} style={{
      top: `${mark.top}%`,
      left: `${mark.left}%`,
      width: `${mark.width}%`,
      height: `${mark.height}%`
    }} />)}
            <Anchor className="image-fallback" href={shot.vendor ? shot.creditHref || shot.src : shot.src} rel="noopener noreferrer" target="_blank">{icon('external')} {shot.vendor ? labels.openVendorPage : labels.openScreenshot}<span>{shot.vendor ? labels.vendorImageUnavailable : labels.imageUnavailable}</span></Anchor>
            <button aria-label={message('enlargeScreenshot', {
      description: shot.alt
    })} className="zoom-button" onClick={() => openZoom(shot)} type="button">{icon('zoom')}</button>
          </div>
          <Figcaption>
            {shot.caption}{shot.credit ? <> · {shot.creditHref ? link(shot.creditHref, shot.credit) : shot.credit}</> : null}
            {shot.version || shot.captured ? <span className="meta">{[shot.version, shot.captured ? message('captured', {
      date: shot.captured
    }) : null].filter(Boolean).join(' · ')}</span> : null}
          </Figcaption>
        </Figure>
      </>;
  };
  const renderLinkVisual = visual => <>
      <span className="screenshot-tag">{icon('external')} {visual.tag || labels.vendorGuideTag}</span>
      <div className="link-visual">
        {visual.title ? <strong>{visual.title}</strong> : null}
        {visual.text ? <p>{rich(visual.text)}</p> : null}
        {(visual.links || []).map((item, i) => <Anchor className="vendor-link" href={item.href} key={i} rel="noopener noreferrer" target="_blank">
            {icon(item.icon || 'book')}<span>{item.label}{item.detail ? <small>{item.detail}</small> : null}</span>{icon('external')}<span className="sr-only">{labels.opensInNewTab}</span>
          </Anchor>)}
      </div>
    </>;
  return <div className="kombify-client-guide not-prose" id={id} dir={direction} lang={locale} ref={rootRef} style={{
    '--kcg-steps': count
  }}>
      <div className="guide-content">
        <div className="page-top">
          <div className="intro-meta">{meta.map((item, i) => <span key={i}>{icon(item.icon)} {item.text}</span>)}</div>
          <div className="page-tools"><button aria-label={labels.printGuide} className="tool-button" onClick={() => window.print()} type="button">{icon('print')}</button></div>
        </div>
        {requirements.length ? <div className="ready-strip">
            <strong>{labels.requirementsTitle}</strong>
            {requirements.map((item, i) => <span key={i}>{icon('check')} {rich(item)}</span>)}
            {requirementsHelp ? <Anchor href={`#${requirementsHelp.target}`} onClick={() => reveal(requirementsHelp.target)}>{requirementsHelp.label} {icon('arrow')}</Anchor> : null}
          </div> : null}

        {apps.length ? <section aria-labelledby={`${id}-apps-title`} className="downloads" id={`${id}-apps`}>
            <div className="section-top">
              <h2 id={`${id}-apps-title`}>{appsTitle}</h2>
              {vendor ? link(vendor.href, vendor.label, 'small-link') : null}
            </div>
            <div className="downloads-grid">
              {apps.map((app, i) => <Anchor className="download-card" href={app.href} key={i} rel="noopener noreferrer" target="_blank">
                  <span className="platform-icon">{icon(app.platform)}</span>
                  <span className="download-text">
                    <strong>{app.label}</strong>
                    <small>{app.detail}</small>
                    <span className="store-name">{app.store} {icon('external')}</span>
                    <span className={`badge ${app.official ? 'official' : 'unofficial'}`}>{app.official ? message('officialApp', {
    vendor: app.vendor
  }) : message('thirdPartyApp', {
    vendor: app.vendor
  })}</span>
                  </span>
                  <span className="sr-only">{labels.opensInNewTab}</span>
                </Anchor>)}
            </div>
            {appsNote ? <p className="download-hint">{rich(appsNote)}</p> : null}
          </section> : null}

        <section aria-labelledby={`${id}-guide-title`} className="guide-section" id={`${id}-guide`}>
          <div className="guide-heading"><h2 id={`${id}-guide-title`}>{stepsTitle}</h2></div>
          <div className="wizard">
            <div aria-label={labels.setupSteps} className="step-tabs" onKeyDown={onTabKey} role="tablist">
              {steps.map((step, i) => <button aria-controls={`${id}-panel-${i}`} aria-selected={i === current} className={`step-tab${completed[i] ? ' done' : ''}`} id={`${id}-tab-${i}`} key={i} onClick={() => select(i)} role="tab" tabIndex={i === current ? 0 : -1} type="button">
                  <span className="step-dot">{completed[i] ? '✓' : number.format(i + 1)}</span><span>{step.tab}</span>
                </button>)}
            </div>
            {steps.map((step, i) => <Article aria-labelledby={`${id}-tab-${i}`} className={`guide-panel${i === current ? ' active' : ''}`} id={`${id}-panel-${i}`} key={i} role="tabpanel">
                <div className="panel-copy">
                  <div className="step-kicker">{message('stepPosition', {
    current: stepNumber.format(i + 1),
    count: stepNumber.format(count)
  })}</div>
                  <h3>{step.title}</h3>
                  {step.intro ? <p className="step-intro">{rich(step.intro)}</p> : null}
                  {step.clicks?.length ? <ol className="click-list">{step.clicks.map((click, j) => <li key={j}><span className="click-num">{number.format(j + 1)}</span><span>{rich(click)}</span></li>)}</ol> : null}
                  {step.verify?.length ? <div className="verify-list">
                      {step.verify.map((item, j) => <label key={j}><input checked={Boolean(verified[i]?.[j])} id={`${id}-verify-${i}-${j}`} onChange={event => onVerify(i, j, event.target.checked)} type="checkbox" /><span>{rich(item)}</span></label>)}
                    </div> : null}
                  {step.note ? <div className="micro-note">{icon('info')}<span>{rich(step.note)}</span></div> : null}
                  {(step.faq ? [].concat(step.faq) : []).map((faq, j) => <Details key={j}><Summary>{faq.q}</Summary><p>{rich(faq.a)}</p></Details>)}
                  {step.check ? <div className="step-check">{icon('ok')} {rich(step.check)}</div> : null}
                </div>
                <div className="panel-visual">
                  {step.screenshot ? renderShot(step.screenshot, i) : step.visual ? renderLinkVisual(step.visual) : null}
                </div>
              </Article>)}
            <div className="wizard-bottom">
              <div className="progress-note">
                <span>{message('progress', {
    done: number.format(completed.filter(Boolean).length),
    count: number.format(count)
  })}</span>
                <div aria-hidden="true" className="progress-meter">{steps.map((step, i) => <span className={completed[i] ? 'done' : undefined} key={i} />)}</div>
              </div>
              <button className="prev" disabled={current === 0} onClick={() => select(current - 1, true)} type="button">{icon('back')} {labels.back}</button>
              <button className="next" onClick={onNext} type="button"><span>{current === last ? labels.finish : labels.next}</span>{icon('arrow')}</button>
            </div>
          </div>
          {sources ? <p className="provenance-inline">{sources.summary} <Anchor href={`#${id}-sources`} onClick={() => reveal(`${id}-sources-detail`)}>{labels.imageSources}</Anchor></p> : null}
        </section>

        {next.length ? <section aria-labelledby={`${id}-more-title`} className="more-section" id={`${id}-more`}>
            <div className="section-top"><h2 id={`${id}-more-title`}>{nextTitle}</h2></div>
            <div className="more-grid">
              {next.map((item, i) => link(item.href, <>
                  <span className="more-icon">{icon(item.icon || 'arrow')}</span>
                  <span><strong>{item.title}</strong><small>{item.text}</small></span>
                </>, 'more-card', i))}
            </div>
          </section> : null}

        {help.length ? <section aria-labelledby={`${id}-help-title`} className="faq-section" id={`${id}-help`}>
            <h2 id={`${id}-help-title`}>{helpTitle}</h2>
            {help.map((item, i) => <Details className="faq" id={item.id} key={i}><Summary>{item.q}</Summary><div className="answer">{rich(item.a)}</div></Details>)}
          </section> : null}

        <Footer className="footline">
          <div className="attribution">{attribution ? rich(attribution) : null}</div>
          <button className="reset" onClick={onReset} type="button">{labels.resetProgress}</button>
        </Footer>

        {sources ? <section className="source-section" id={`${id}-sources`}>
            <Details id={`${id}-sources-detail`}>
              <Summary>{labels.sourcesTitle}</Summary>
              <div className="source-content">
                {(sources.paragraphs || []).map((text, i) => <p key={i}>{rich(text)}</p>)}
                <div className="source-links">{(sources.links || []).map((item, i) => link(item.href, item.label, undefined, i))}</div>
              </div>
            </Details>
            <div className="dim">{labels.ownershipNotice}</div>
          </section> : null}
      </div>

      <Dialog aria-labelledby={`${id}-zoom-title`} className="zoom-dialog" onClick={closeOnBackdrop} ref={zoomRef}>
        <div className="dialog-header">
          <h2 id={`${id}-zoom-title`}>{zoom?.vendor ? labels.vendorScreenshot : labels.screenshot}</h2>
          <button aria-label={labels.closeImage} className="dialog-close" onClick={() => zoomRef.current?.close()} type="button">{icon('close')}</button>
        </div>
        <div className="zoom-content">
          {zoom ? <Img alt={zoom.alt} src={zoom.src} /> : null}
          {zoom?.creditHref ? link(zoom.creditHref, zoom.vendor ? labels.openOriginal : labels.aboutScreenshot) : null}
        </div>
      </Dialog>
      <div aria-live="polite" className="sr-only" role="status">{toast}</div>
      <div aria-hidden="true" className={`toast${toast ? ' show' : ''}`}>{toast}</div>
    </div>;
};

export const clientSetupLabelsAr = {
  appsTitle: 'ابدأ بتنزيل التطبيق.',
  stepsTitle: 'اتصل خطوة بخطوة.',
  helpTitle: 'هل تحتاج إلى مساعدة؟',
  nextTitle: 'ما الخطوة التالية.',
  opensInNewTab: ' (يُفتح في علامة تبويب جديدة)',
  verifyRequired: 'ضع علامة على كل نقطة بعد أن تتحقق منها بنفسك.',
  allDone: 'جميع الخطوات مُعلَّمة كمكتملة في هذا المتصفح.',
  remainingSteps: '{done} من {count} خطوات مُعلَّمة كمكتملة. افتح علامات التبويب الأخرى لإكمالها.',
  progressReset: 'تمت إعادة ضبط تقدمك في هذا المتصفح.',
  vendorScreenshotTag: 'لقطة شاشة من المطوّر',
  kombifyScreenshotTag: 'لقطة شاشة من kombify',
  openVendorPage: 'افتح صفحة المطوّر',
  openScreenshot: 'افتح لقطة الشاشة',
  vendorImageUnavailable: 'يتطلب تحميلها اتصالاً بالإنترنت.',
  imageUnavailable: 'تعذّر تحميل الصورة.',
  enlargeScreenshot: 'تكبير لقطة الشاشة: {description}',
  captured: 'التُقطت في {date}',
  vendorGuideTag: 'دليل المطوّر',
  printGuide: 'اطبع الدليل',
  requirementsTitle: 'ما تحتاج إليه',
  officialApp: 'رسمي · {vendor}',
  thirdPartyApp: 'جهة خارجية · {vendor}',
  setupSteps: 'خطوات الإعداد',
  stepPosition: 'الخطوة {current} / {count}',
  progress: 'اكتملت {done} من {count} خطوات',
  back: 'رجوع',
  finish: 'إنهاء',
  next: 'تم · التالي',
  imageSources: 'مصادر الصور والتاريخ',
  resetProgress: 'إعادة ضبط التقدم',
  sourcesTitle: 'مصادر الصور والروابط التي جرى فحصها والتاريخ',
  ownershipNotice: 'دليل من kombify · أسماء المنتجات ولقطات شاشة تطبيقات المطوّرين والعلامات التجارية مملوكة لأصحابها.',
  vendorScreenshot: 'لقطة شاشة من المطوّر',
  screenshot: 'لقطة شاشة',
  closeImage: 'إغلاق الصورة',
  openOriginal: 'افتح الأصل من المطوّر',
  aboutScreenshot: 'حول لقطة الشاشة هذه'
};

<ClientSetupGuide
  labels={clientSetupLabelsAr}
  locale="ar"
  direction="rtl"
  id="kcg-passwords"
  meta={[
{ icon: "phone", text: "الهاتف والمتصفح والحاسوب" },
{ icon: "steps", text: "6 خطوات قصيرة" },
{ icon: "book", text: "لا حاجة إلى معرفة مسبقة" },
]}
  requirements={[
"عنوان خزنتك، مثل https://vault.home.test",
"دعوة على عنوان بريدك الإلكتروني",
"كل جهاز مُعدّ لخزنة منزلك من قِبل الشخص الذي أعدّ kombify",
"كلمة مرور رئيسية يمكنك تذكّرها",
]}
  requirementsHelp={{ label: "ليست لديك دعوة بعد؟", target: "kcg-passwords-no-invite" }}
  appsTitle="ابدأ بتنزيل تطبيق Bitwarden."
  vendor={{ label: "كل التنزيلات من Bitwarden", href: "https://bitwarden.com/download/" }}
  apps={[
{ platform: "apple", label: "iPhone وiPad", detail: "Bitwarden Password Manager", store: "افتح في App Store", href: "https://apps.apple.com/app/bitwarden-password-manager/id1137397744", vendor: "Bitwarden", official: true },
{ platform: "android", label: "Android", detail: "Bitwarden Password Manager", store: "افتح في Google Play", href: "https://play.google.com/store/apps/details?id=com.x8bit.bitwarden", vendor: "Bitwarden", official: true },
{ platform: "browser", label: "إضافة المتصفح", detail: "Chrome وFirefox وEdge وSafari وغيرها", store: "افتح صفحة تنزيل Bitwarden", href: "https://bitwarden.com/download/", vendor: "Bitwarden", official: true },
{ platform: "desktop", label: "الحاسوب", detail: "Windows وmacOS وLinux", store: "افتح صفحة تنزيل Bitwarden", href: "https://bitwarden.com/download/", vendor: "Bitwarden", official: true },
]}
  appsNote="متاجر المتصفحات: [Chrome](https://chromewebstore.google.com/detail/bitwarden-password-manager/nngceckbapebfimnlniiiahkandclblb) · [Firefox](https://addons.mozilla.org/firefox/addon/bitwarden-password-manager/) · [Edge](https://microsoftedge.microsoft.com/addons/detail/bitwarden-password-manager/jbkfoedolllekgbhcbcoahefnbanhhlh) · [Safari (Mac App Store)](https://apps.apple.com/app/bitwarden/id1352778147). تعمل خزنتك على Vaultwarden، وهو يعمل مع تطبيقات Bitwarden الرسمية هذه. لا تحتاج إلى تطبيق Vaultwarden منفصل."
  stepsTitle="أعِدّ خزنتك خطوة بخطوة."
  steps={[
{
  tab: "فتح الخزنة",
  title: "افتح خزنتك في المتصفح.",
  intro: "ابدأ من حاسوب. لخزنتك عنوان ويب خاص بها، مثل موقع لا يستخدمه إلا أفراد منزلك.",
  clicks: [
    "اكتب عنوان خزنتك في شريط عنوان المتصفح، مثل **https://vault.home.test**، ثم اضغط Enter.",
    "أسفل مربع تسجيل الدخول، انقر [[Create account]].",
  ],
  note: "العنوان في هذا الدليل مجرد مثال. استخدم العنوان الذي حصلت عليه من الشخص الذي أعدّ kombify.",
  faq: { q: "ما عنوان الخزنة؟", a: "هو عنوان الويب الخاص بخزنة كلمات المرور في منزلك. يبدأ عادةً بـ **https://vault.** وينتهي باسم شبكة منزلك. يستطيع الشخص الذي أعدّ kombify إخبارك بالعنوان الدقيق." },
  check: "ترى نموذج [[Create account]].",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-01-open-vault.webp", width: 1088, height: 830, alt: "صفحة تسجيل الدخول إلى Vaultwarden مع تمييز رابط Create account", caption: "صفحة تسجيل الدخول إلى الخزنة", credit: "لقطة شاشة من kombify", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · web vault 2026.7.0", captured: "2026-09-24", annotations: [{ n: 2, top: 84.3, left: 38.3, width: 23.5, height: 7.2 }] },
},
{
  tab: "إنشاء الحساب",
  title: "أنشئ حسابك.",
  intro: "لا تقبل خزنتك إلا عناوين البريد الإلكتروني المدعوّة. استخدم العنوان نفسه الذي وصلته الدعوة عليه.",
  clicks: [
    "في [[Email address]]، أدخل عنوان بريدك الإلكتروني المدعوّ.",
    "في [[Name]]، أدخل اسمك. يستطيع الشخص الذي يدير الخزنة، وكل من تشارك معه كلمات المرور، رؤيته.",
    "انقر [[Continue]].",
  ],
  faq: { q: "هل هذا حسابي في kombify؟", a: "لا. هذا الحساب يخص خزنة كلمات المرور فقط. له عنوان بريد إلكتروني وكلمة مرور رئيسية خاصان به." },
  check: "تطلب الصفحة الآن [[Set a strong password]].",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-02-create-account.webp", width: 1088, height: 718, alt: "نموذج Create account مع عنوان البريد alex@example.com والاسم Alex Example", caption: "Create account", credit: "لقطة شاشة من kombify", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · web vault 2026.7.0", captured: "2026-09-24", annotations: [{ n: 1, top: 37.6, left: 16.4, width: 65.1, height: 13.4 }, { n: 2, top: 61, left: 16.4, width: 65.1, height: 13.4 }, { n: 3, top: 76.3, left: 14, width: 72.1, height: 13.9 }] },
},
{
  tab: "كلمة المرور الرئيسية",
  title: "اختر كلمة مرورك الرئيسية.",
  intro: "كلمة المرور الرئيسية هي كلمة المرور الوحيدة التي ما زلت بحاجة إلى تذكّرها. فهي تفتح كل الكلمات الأخرى.",
  clicks: [
    "في [[Master password]]، أدخل كلمة مرور طويلة. جملة قصيرة من أربع كلمات أو أكثر خيار جيد.",
    "أدخل كلمة المرور نفسها مرة أخرى في [[Confirm master password]].",
    "انقر [[Create account]]. إذا اقترحت الصفحة إضافة المتصفح، فانقر [[Add it later]] ثم [[Skip to web app]]. ستربط الإضافة في الخطوة 5.",
  ],
  note: "**لا يستطيع أحد استعادة كلمة مرور رئيسية منسية**، ولا حتى الشخص الذي يدير خزنتك. دوّنها واحتفظ بالورقة في مكان آمن خارج الخزنة.",
  faq: { q: "ماذا يعني شريط القوة؟", a: "يقدّر مدى صعوبة تخمين كلمة مرورك. استهدف مستوى **Strong**. الطول أفضل من التعقيد." },
  check: "تُفتح خزنتك الفارغة بعنوان [[All vaults]].",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-03-master-password.webp", width: 1088, height: 1310, alt: "صفحة Set a strong password مع كلمة المرور الرئيسية مُدخلة مرتين وتقييمها Strong", caption: "Set a strong password", credit: "لقطة شاشة من kombify", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · web vault 2026.7.0", captured: "2026-09-24", annotations: [{ n: 1, top: 25.5, left: 16.4, width: 60.7, height: 7.3 }, { n: 2, top: 52.2, left: 16.4, width: 60.7, height: 7.3 }, { n: 3, top: 87, left: 14, width: 72.1, height: 7.6 }] },
},
{
  tab: "أول كلمة مرور",
  title: "احفظ أول كلمة مرور.",
  intro: "احفظ تسجيل دخول واحدًا للتجربة. سيُظهر لاحقًا أن تطبيقاتك متصلة بخزنتك.",
  clicks: [
    "في أعلى اليمين، انقر [[New]] واختر [[Login]]. إذا ظهرت نافذة ترحيب أولًا، فانقر [[Skip]].",
    "في [[Item name]]، أدخل اسمًا تتعرّف عليه، مثل اسم متجر.",
    "أدخل [[Username]]. بجوار [[Password]]، انقر السهمين الدائريين لإنشاء كلمة مرور، ثم انقر [[Use this password]].",
    "انقر [[Save]].",
  ],
  note: "أضف عنوان ويب المتجر تحت [[Website (URI)]]. عندها تقترح إضافة المتصفح تسجيل الدخول هذا على ذلك الموقع.",
  check: "تظهر الرسالة [[Item added]] ويظهر تسجيل دخولك في القائمة.",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-04-new-login.webp", width: 1472, height: 1664, alt: "نافذة New Login مع اسم العنصر Example Shop واسم مستخدم وكلمة مرور مُنشأة", caption: "New Login", credit: "لقطة شاشة من kombify", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · web vault 2026.7.0", captured: "2026-09-24", annotations: [{ n: 2, top: 12.1, left: 7.9, width: 82.6, height: 5.8 }, { n: 3, top: 41.8, left: 7.9, width: 79.3, height: 5.8 }, { n: 3, top: 52.3, left: 87.5, width: 5.7, height: 5 }, { n: 4, top: 92.1, left: 2.7, width: 10.4, height: 6 }] },
},
{
  tab: "ربط التطبيقات",
  title: "اربط تطبيقات Bitwarden.",
  intro: "يتصل كل تطبيق Bitwarden أولًا بخوادم Bitwarden نفسها. أخبره مرة واحدة أن يستخدم خزنتك بدلًا منها.",
  clicks: [
    "ثبّت تطبيق Bitwarden من القائمة أعلاه وافتحه.",
    "في شاشة تسجيل الدخول، افتح القائمة [[Logging in on]] واختر [[Self-hosted]]. في تطبيق الحاسوب تُسمى القائمة [[Accessing]].",
    "في [[Server URL]]، أدخل عنوان خزنتك مع **https://** في البداية، ثم اضغط [[Save]].",
    "سجّل الدخول ببريدك الإلكتروني وكلمة مرورك الرئيسية.",
  ],
  note: "كرّر هذه الخطوات على كل هاتف ومتصفح وحاسوب تستخدمه. يحتاج كل منها إلى عنوان خزنتك مرة واحدة.",
  faq: { q: "لماذا لا توجد صورة للتطبيق هنا؟", a: "لا تمنح شروط Bitwarden إذنًا بإعادة استخدام صورها. يعرض دليلها الخاص كل شاشة، والتسميات أعلاه تطابقه." },
  check: "يعرض التطبيق تسجيل الدخول الذي حفظته في الخطوة 4.",
  visual: {
    tag: "دليل BITWARDEN",
    title: "تعرض Bitwarden كل شاشة",
    text: "اختر جهازك في دليل Bitwarden. ابحث عن القسم الخاص بالخادم **المستضاف ذاتيًا**.",
    links: [
      { label: "ربط تطبيق بخادمك الخاص", detail: "bitwarden.com · كل الأجهزة", href: "https://bitwarden.com/help/change-client-environment/", icon: "server" },
      { label: "البدء مع إضافة المتصفح", detail: "bitwarden.com", href: "https://bitwarden.com/help/getting-started-browserext/", icon: "browser" },
      { label: "البدء مع تطبيق الهاتف", detail: "bitwarden.com", href: "https://bitwarden.com/help/getting-started-mobile/", icon: "phone" },
    ],
  },
},
{
  tab: "الفحص",
  title: "هل كل شيء متصل؟",
  intro: "افحص ذلك في خزنة الويب وفي تطبيق واحد. ضع علامة فقط على ما فحصته بنفسك.",
  verify: [
    "أستطيع فتح عنوان خزنتي وتسجيل الدخول.",
    "يظهر تسجيل الدخول الذي حفظته في تطبيق Bitwarden على هاتفي أو متصفحي أو حاسوبي.",
    "كلمة مروري الرئيسية مدوّنة ومحفوظة خارج الخزنة.",
  ],
  note: "لا يقرأ هذا الدليل خزنتك. تبقى علاماتك في هذا المتصفح.",
  check: "يمكنك الآن نقل كلمات مرورك الأخرى إلى الخزنة.",
  screenshot: { src: "/images/guides/passwords/vaultwarden/web-05-first-item.webp", width: 1430, height: 300, alt: "قائمة All vaults تعرض تسجيل الدخول المحفوظ Example Shop", caption: "أول تسجيل دخول في الخزنة", credit: "لقطة شاشة من kombify", creditHref: "#kcg-passwords-sources", version: "Vaultwarden 1.37.2 · web vault 2026.7.0", captured: "2026-09-24", annotations: [{ n: null, top: 37.2, left: 1, width: 98, height: 58.1 }] },
},
]}
  nextTitle="ما الخطوة التالية."
  next={[
{ icon: "shield", title: "فعّل تسجيل الدخول بخطوتين", text: "تشرح Bitwarden كيفية إضافة خطوة ثانية لتسجيل الدخول.", href: "https://bitwarden.com/help/setup-two-step-login/" },
{ icon: "server", title: "انسخ الخزنة احتياطيًا", text: "للشخص الذي يشغّل kombify: احمِ بيانات الخزنة.", href: "/ar/guides/stackkits/back-up-and-restore" },
]}
  help={[
{ id: "kcg-passwords-no-invite", q: "ليس لدي عنوان خزنة أو دعوة بعد.", a: "اسأل الشخص الذي أعدّ kombify في منزلك. يضيف خدمة كلمات المرور ويدعو عنوان بريدك الإلكتروني. [كيف تعمل كلمات المرور مع kombify](/ar/guides/stackkits/use-cases/passwords) · [إعداد المالك](/ar/stackkits/apps/vaultwarden)." },
{ q: "تقول Create account: “Registration not allowed or user already exists”.", a: "تأكد من أنك تستخدم عنوان البريد الإلكتروني المدعوّ نفسه تمامًا. إذا كنت قد أنشأت حسابك بالفعل، فارجع وسجّل الدخول بدلًا من ذلك. وإلا فاطلب دعوة جديدة." },
{ q: "لا يُفتح العنوان، أو يحذّر المتصفح من الاتصال.", a: "جرّب العنوان أولًا على جهاز داخل شبكة منزلك. إذا كانت خزنتك تعمل في المنزل فقط، فاتصل بشبكة Wi-Fi المنزلية أو بتطبيق الاتصال المنزلي الذي زُوّدت به. يجب أيضًا إعداد كل جهاز ليثق بخادم منزلك؛ ويتولى ذلك الشخص الذي أعدّ kombify. إذا قال المتصفح إن الاتصال ليس خاصًا، فتوقف هنا واسأله. لا تتجاوز التحذير. [حول عناوين المنزل](/ar/guides/stackkits/use-cases/network)." },
{ q: "نسيت كلمة مروري الرئيسية.", a: "لا يستطيع أحد استعادتها. فخزنتك مشفّرة بها. يستطيع الشخص الذي يدير خزنتك حذف حسابك لتبدأ من جديد، لكن كلمات المرور المحفوظة فيه تضيع. [Bitwarden حول كلمات المرور الرئيسية](https://bitwarden.com/help/master-password/)." },
{ q: "هاتف Android لدي بلا Google Play.", a: "تشغّل Bitwarden مستودع F-Droid خاصًا بها. العنوان مذكور في [صفحة تنزيل Bitwarden](https://bitwarden.com/download/)." },
{ q: "لماذا يُذكر Vaultwarden وBitwarden معًا؟", a: "Vaultwarden هو البرنامج الذي يشغّل خزنتك. وهو خادم غير رسمي يعمل مع تطبيقات Bitwarden الرسمية. Vaultwarden غير مرتبط بشركة Bitwarden, Inc. تعرض الصور Vaultwarden 1.37.2 بالإنجليزية؛ وقد تبدو الإصدارات الأحدث واللغات الأخرى مختلفة." },
]}
  attribution="**يشغّل Vaultwarden خزنتك، وتفتحها تطبيقات Bitwarden. يثبّته kombify لك.** لا تصنع kombify أيًّا من التطبيقين. [Vaultwarden](https://github.com/dani-garcia/vaultwarden) (AGPL-3.0) · خزنة الويب: [عميل ويب Bitwarden المبني لـ Vaultwarden](https://github.com/dani-garcia/bw_web_builds) (GPL-3.0) · [Bitwarden](https://bitwarden.com/)"
  sources={{
summary: "لقطات شاشة من kombify من تثبيت Vaultwarden محلي · حساب مُختلَق · قوائم بالإنجليزية.",
paragraphs: [
  "**لقطات الشاشة · 24 سبتمبر 2026.** التقطت kombify صور خزنة الويب من تثبيت مرجعي محلي: Vaultwarden 1.37.2، وهي الصورة التي يوفّرها كتالوج StackKits لكلمات المرور، مع خزنة الويب المضمّنة 2026.7.0 (عميل ويب Bitwarden، GPL-3.0). استخدم التثبيت العنوان التجريبي https://vault.home.test والحساب المُختلَق alex@example.com. وهو تثبيت مرجعي وليس اختبار نشر لـ StackKits. وقد أضاف هذا الدليل العلامات البنفسجية.",
  "لا تُعرض شاشات تطبيق Bitwarden. [شروط Bitwarden](https://bitwarden.com/terms/) لا تمنح إذنًا بإعادة استخدام محتواها، لذا تربط الخطوة 5 بدليل Bitwarden نفسه.",
  "جرى فحص روابط المتاجر وصفحات المساعدة في 24 سبتمبر 2026. يبقى تقدمك في هذا المتصفح. لا يربط الدليل أي حسابات ولا يطلب أي كلمات مرور.",
],
links: [
  { label: "Bitwarden: ربط التطبيقات الفردية", href: "https://bitwarden.com/help/change-client-environment/" },
  { label: "تنزيلات Bitwarden", href: "https://bitwarden.com/download/" },
  { label: "مشروع Vaultwarden", href: "https://github.com/dani-garcia/vaultwarden" },
],
}}
/>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.