I’ve had to implement a number of imperative workarounds for OnlyOffice to get fonts to work correctly. Without knowing any details about your configuration, I think the best way to implement what I think you want (which is a custom template entry) would be to append it with a Home manager activation script (assuming you are using Home manager).
Here is an example implementation using my configuration as a template:
{
config,
lib,
pkgs,
…
}:
# Workaround for OnlyOffice font issue:
# https://github.com/NixOS/nixpkgs/issues/373521
let
hmFonts = “${config.home.profileDirectory}/share/fonts”;
ooFonts = “${config.xdg.dataHome}/fonts/onlyoffice”; # ~/.local/share/fonts/onlyoffice
in
{
home.packages = with pkgs; [
hunspell # Dictionary
hunspellDicts.en_US
];
programs.onlyoffice = {
enable = true;
settings = {
UITheme = “theme-night”; # the internal ID for Modern Dark
};
};
# Populate ~/.local/share/fonts with ttf files (not symlinks)
home.activation = {
onlyofficeUserFonts = lib.hm.dag.entryAfter [ “writeBoundary” ] # sh
''
set -eu
rm -rf "${ooFonts}"
mkdir -p "${ooFonts}"
# Copy actual files (dereference symlinks with -L)
if [ -d "${hmFonts}" ]; then
${pkgs.rsync}/bin/rsync -aL \
--include='*/' --include='*.ttf' --include='*.otf' --exclude='*' \
"${hmFonts}/" "${ooFonts}/"
fi
chmod -R 744 "${ooFonts}"
${pkgs.findutils}/bin/find "${ooFonts}" -type f \( -name '*.ttf' -o -name '*.otf' \) -exec chmod 0644 {} \;
${pkgs.fontconfig}/bin/fc-cache -f "${ooFonts}" >/dev/null 2>&1 || true
'';
onlyofficeTemplates = lib.hm.dag.entryAfter [ "writeBoundary" "onlyofficeUserFonts" ] # sh
''
set -eu
TEMPLATES_FILE="${config.xdg.dataHome}/onlyoffice/desktopeditors/templates.xml"
MY_TEMPLATE_PATH="${config.home.homeDirectory}/Templates/my-template.docx"
MY_TEMPLATE_NAME="My Custom Template"
if [ ! -f "$TEMPLATES_FILE" ]; then
printf "templates.xml not found, skipping (OnlyOffice will create it on first launch)\n"
exit 0
fi
if ${pkgs.gnugrep}/bin/grep -qF "$MY_TEMPLATE_PATH" "$TEMPLATES_FILE"; then
printf "Custom template already present, nothing to do\n"
exit 0
fi
# Determine the next available template ID
LAST_ID=$(${pkgs.gnugrep}/bin/grep -oP 'id="\K[0-9]+' "$TEMPLATES_FILE" | sort -n | tail -1)
NEXT_ID=$(( LAST_ID + 1 ))
# Insert the new template entry before the </templates> tag
${pkgs.gnused}/bin/sed -i \
"s|</templates>|\t<template id=\"$NEXT_ID\" name=\"$MY_TEMPLATE_NAME\" path=\"$MY_TEMPLATE_PATH\" pin=\"0\" format=\"65\" />\n</templates>|" \
"$TEMPLATES_FILE"
'';
};
}
You can read documentation on home.activation scripts here:
And here:
Basically it lets you define a ordered list of scripts that will run when activating your new configuration. In this example I define two scripts: onlyofficeUserFonts, and onlyofficeTemplates that will run on activation, and you should see them listed in the activation output:
Activating onlyofficeUserFonts
Activating onlyofficeTemplates
The template script assumes you have XDG paths configured and just has a placeholder name for your template here:
TEMPLATES_FILE="${config.xdg.dataHome}/onlyoffice/desktopeditors/templates.xml"
MY_TEMPLATE_PATH="${config.home.homeDirectory}/Templates/my-template.docx"
MY_TEMPLATE_NAME="My Custom Template"
You will want to change these variables to match the correct paths, filenames, and templates you want to use, but you should be able to figure that out from this example.
Why is this all so complicated? Well, for a single user on a single machine, it probably isn’t worth all this effort, but if you were going to provision 25 machines for 50 different users in a business it would make much more sense. You could have templates defined for people in sales, and people in marketing, and then programmatically configure templates based on work roles, etc. and manage them all in a single repository.
Hope this helps. Good luck.