penpot/frontend/src/app/util/text/layout.cljs
alonso.torres 09572a1d5b ✨ Replace the CJK layout toggles with a text Language panel
The CJK text options were behind per-language "Enable layout" toggles in
the file menu and the settings, each with its own sidebar section. A text
now has one language, picked in a single Language panel, and the options
of that language show below it.

- Rename the `vertical-text-layout` flag and feature to `cjk-support`.
- Remove the per-file and per-profile layout toggles, the file options
  that stored them and the `:set-text-layout` change.
- Add the Language panel: a grouped dropdown of Japanese, Korean and the
  regional Chinese variants, a row to change the language and a button to
  remove it, "Mixed" when the selected texts differ. Picking a language
  writes it to every paragraph of the texts.
- Render the CJK attrs only under the language that uses them, so a text
  without language is horizontal and plain. The stored content keeps
  every attr.
- Remember the last picked language for the next new texts.
- Add File > Language: the language of the texts without one of their
  own, applied at render time and laid out again when it changes.
- Add the profile text language in Settings > Options: new files start
  with it as their file language.
- Extract the grouped dropdown of the board size presets into a shared
  component used by the presets and the Language panel.
- Name the Japanese readings furigana, drop the redundant prefixes of
  the furigana and pinyin options, move Distribute below the writing
  mode row and show only the position sides of the writing mode.

AI-assisted-by: claude-opus-5-5
2026-11-12 00:49:45 +01:00

73 lines
3.5 KiB
Clojure

;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS SUBSIDIARY SL
(ns app.util.text.layout
"Language of text shapes, as the CJK text options read it. A text has one
language: every paragraph carries the same `:text-language` tag. A text
without one takes the file language."
(:require
[app.common.types.text :as txt]
[app.util.i18n :refer [tr]]))
(defn- get-paragraph-languages
"Language of each paragraph of `content`, `default-language` for the ones
without; a content without paragraphs reads as one such paragraph."
[content default-language]
(let [paragraphs (txt/node-seq txt/is-paragraph-node? content)]
(if (seq paragraphs)
(map #(or (:text-language %) default-language) paragraphs)
[default-language])))
(defn get-texts-language
"Language of the text `contents`: the tag all their paragraphs share, nil
when none has a language, `:multiple` when they differ. A paragraph
without language takes `default-language`, so with none it differs from
one with a language."
([contents]
(get-texts-language contents nil))
([contents default-language]
(let [languages (into #{} (mapcat #(get-paragraph-languages % default-language)) contents)]
(if (> (count languages) 1)
:multiple
(first languages)))))
(defn language-label
"Name of the language `tag` in the Language panel row: \"Mixed\" for
`:multiple`, the tag itself when it is not one of the listed languages."
[tag]
(case tag
:multiple (tr "settings.multiple")
"ja" (tr "workspace.options.text-options.profile-japanese")
"ko" (tr "workspace.options.text-options.profile-korean")
"zh-Hans-CN" (tr "workspace.options.text-options.language-chinese-variant"
(tr "workspace.options.text-options.profile-chinese-mainland-simplified"))
"zh-Hant-CN" (tr "workspace.options.text-options.language-chinese-variant"
(tr "workspace.options.text-options.profile-chinese-mainland-traditional"))
"zh-Hant-TW" (tr "workspace.options.text-options.language-chinese-variant"
(tr "workspace.options.text-options.profile-chinese-taiwan"))
"zh-Hant-HK" (tr "workspace.options.text-options.language-chinese-variant"
(tr "workspace.options.text-options.profile-chinese-hong-kong"))
tag))
(defn language-options
"Rows of the language dropdown: one group per language, the `selected`
tag checked."
[selected]
(let [option (fn [tag label]
{:id tag :label label :selected (= selected tag)})]
[{:id "japanese" :header true
:label (tr "workspace.options.text-options.language-group-japanese")}
(option "ja" (tr "workspace.options.text-options.profile-japanese"))
{:id "korean" :header true
:label (tr "workspace.options.text-options.language-group-korean")}
(option "ko" (tr "workspace.options.text-options.profile-korean"))
{:id "chinese" :header true
:label (tr "workspace.options.text-options.language-group-chinese")}
(option "zh-Hans-CN" (tr "workspace.options.text-options.profile-chinese-mainland-simplified"))
(option "zh-Hant-CN" (tr "workspace.options.text-options.profile-chinese-mainland-traditional"))
(option "zh-Hant-TW" (tr "workspace.options.text-options.profile-chinese-taiwan"))
(option "zh-Hant-HK" (tr "workspace.options.text-options.profile-chinese-hong-kong"))]))