Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ Private Dateien werden nie über öffentliche Medien-URLs ausgeliefert: Download
- Der optionale Whitelist-Modus fügt eine zweite Autorisierungsebene für ausgewählte Benutzer hinzu.
- Ordnerberechtigungen beschränken den Zugriff auf die gewährten Benutzer, Gruppen und Aktionen, mit Vererbung von übergeordneten Ordnern. Ordner ohne Regeln behalten das capability-basierte Verhalten, und Administratoren behalten immer vollen Zugriff.
- Einstellungen, Gruppen, Kontingente, Benachrichtigungen, Berichte, Protokolle, Whitelist-Verwaltung, Wartungswerkzeuge und Datenkontrollen bei der Deinstallation erfordern `manage_options`.
- Der Standardspeicher ist `wp-content/uploads/private-documents/` und wird durch serverseitige Deny-Dateien geschützt: die generierte `.htaccess` unter Apache und LiteSpeed, die `web.config` unter IIS und eine äquivalente Nginx-Regel, die direkte Anfragen an diesen Pfad verweigert.
- Für besonders sensible Deployments ist ein eigener Speicherpfad außerhalb des öffentlichen Webroots zu bevorzugen. Das Speicher-Widget zeigt nur die Nutzung durch TeamVault.
- Der Standardspeicher ist `wp-content/uploads/private-documents/` und wird durch serverseitige Deny-Dateien geschützt: die generierte `.htaccess` unter Apache und LiteSpeed, die `web.config` unter IIS und eine äquivalente Nginx-Regel, die direkte Anfragen verweigert. Uploads werden abgelehnt, wenn diese Dateien nicht erstellt werden können.
- Empfohlen: ein eigener Speicherpfad außerhalb des öffentlichen Webroots, insbesondere bei Nginx, das `.htaccess` ignoriert. Das Speicher-Widget zeigt nur die Nutzung durch TeamVault.

Siehe [`SECURITY.md`](SECURITY.md) für die Meldung von Schwachstellen.

Expand Down
4 changes: 2 additions & 2 deletions README.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ Los archivos privados nunca se sirven mediante URL públicas de medios: las desc
- La lista de permitidos opcional añade una segunda capa de autorización para los usuarios seleccionados.
- Los permisos por carpeta limitan el acceso a los usuarios, grupos y acciones concedidos, con herencia desde las carpetas principales. Las carpetas sin reglas mantienen el comportamiento basado en la capability, y los administradores conservan siempre el acceso completo.
- Los ajustes, grupos, cuotas, notificaciones, informes, registros, gestión de la lista de permitidos, herramientas de mantenimiento y controles de datos al desinstalar requieren `manage_options`.
- El almacenamiento predeterminado es `wp-content/uploads/private-documents/` y está protegido con archivos de denegación a nivel de servidor: el archivo `.htaccess` generado en Apache y LiteSpeed, el archivo `web.config` en IIS y una regla Nginx equivalente que deniega las solicitudes directas a esa ruta.
- Para despliegues de alta sensibilidad, prefiere una ruta de almacenamiento personalizada fuera de la raíz web pública. El widget de almacenamiento muestra solo el uso de TeamVault.
- El almacenamiento predeterminado es `wp-content/uploads/private-documents/` y está protegido con archivos de denegación a nivel de servidor: el archivo `.htaccess` generado en Apache y LiteSpeed, el archivo `web.config` en IIS y una regla Nginx equivalente que deniega las solicitudes directas. Las subidas se rechazan cuando estos archivos no se pueden crear.
- Recomendado: una ruta de almacenamiento personalizada fuera de la raíz web pública, especialmente en Nginx, que ignora `.htaccess`. El widget de almacenamiento muestra solo el uso de TeamVault.

Consulta [`SECURITY.md`](SECURITY.md) para reportar vulnerabilidades.

Expand Down
4 changes: 2 additions & 2 deletions README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ Les fichiers privés ne sont jamais servis par des URL de médias publiques : le
- La liste d'autorisation facultative ajoute une seconde couche d'autorisation pour les utilisateurs sélectionnés.
- Les autorisations par dossier limitent l'accès aux utilisateurs, groupes et actions accordés, avec héritage depuis les dossiers parents. Les dossiers sans règles conservent le comportement basé sur la capacité, et les administrateurs conservent toujours un accès complet.
- Les réglages, groupes, quotas, notifications, rapports, journaux, gestion de la liste d'autorisation, outils de maintenance et contrôles des données à la désinstallation exigent `manage_options`.
- Le stockage par défaut est `wp-content/uploads/private-documents/` et il est protégé par des fichiers de refus au niveau du serveur : le fichier `.htaccess` généré sur Apache et LiteSpeed, le fichier `web.config` sur IIS et une règle Nginx équivalente qui refuse les requêtes directes vers ce chemin.
- Pour les déploiements à haute sensibilité, préférez un chemin de stockage personnalisé en dehors de la racine web publique. Le widget de stockage affiche uniquement l'utilisation de TeamVault.
- Le stockage par défaut est `wp-content/uploads/private-documents/` et il est protégé par des fichiers de refus au niveau du serveur : le fichier `.htaccess` généré sur Apache et LiteSpeed, le fichier `web.config` sur IIS et une règle Nginx équivalente qui refuse les requêtes directes. Les téléversements sont refusés lorsque ces fichiers ne peuvent pas être créés.
- Recommandé : un chemin de stockage personnalisé en dehors de la racine web publique, en particulier sur Nginx, qui ignore `.htaccess`. Le widget de stockage affiche uniquement l'utilisation de TeamVault.

Consultez [`SECURITY.md`](SECURITY.md) pour signaler une vulnérabilité.

Expand Down
4 changes: 2 additions & 2 deletions README.it.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ I file privati non vengono mai serviti tramite URL pubblici dei media: download
- La modalità whitelist opzionale aggiunge un secondo livello di autorizzazione per gli utenti selezionati.
- I permessi per cartella limitano l'accesso agli utenti, ai gruppi e alle azioni concessi, con ereditarietà dalle cartelle padre. Le cartelle senza regole mantengono il comportamento basato sulla capability e gli Amministratori conservano sempre l'accesso completo.
- Impostazioni, gruppi, quote, notifiche, report, registri, gestione della whitelist, strumenti di manutenzione e controlli sui dati alla disinstallazione richiedono `manage_options`.
- L'archiviazione predefinita è `wp-content/uploads/private-documents/` ed è protetta con file di deny a livello di server: il file `.htaccess` generato su Apache e LiteSpeed, il file `web.config` su IIS e una regola Nginx equivalente che nega le richieste dirette a quel percorso.
- Per installazioni ad alta sensibilità, preferisci un percorso di archiviazione personalizzato all'esterno della webroot pubblica. Il widget di archiviazione mostra solo l'utilizzo di TeamVault.
- L'archiviazione predefinita è `wp-content/uploads/private-documents/` ed è protetta con file di deny a livello di server: il file `.htaccess` generato su Apache e LiteSpeed, il file `web.config` su IIS e una regola Nginx equivalente che nega le richieste dirette. I caricamenti vengono rifiutati quando questi file non possono essere creati.
- Consigliato: un percorso di archiviazione personalizzato all'esterno della webroot pubblica, soprattutto su Nginx, che ignora `.htaccess`. Il widget di archiviazione mostra solo l'utilizzo di TeamVault.

Consulta [`SECURITY.md`](SECURITY.md) per le segnalazioni di vulnerabilità.

Expand Down
67 changes: 44 additions & 23 deletions docs/developer/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,62 @@ translators can collaborate in GlotPress instead of editing PHP.

- All user-facing strings use the `mikesoft-teamvault` text domain
(`__()`, `esc_html__()`, `esc_attr__()`, `esc_html_e()` …).
- `MSTV_I18n::init()` (runs on `init` via `MSTV_Bootstrap::init_services()`)
loads community language packs with the standard call:

```php
load_plugin_textdomain('mikesoft-teamvault', false, dirname(plugin_basename(__FILE__), 2) . '/languages');
```

(`__FILE__` is `includes/class-mstv-i18n.php`, hence dirname level 2.)
- `languages/mikesoft-teamvault.pot` is the translatable-string template
shipped for GlotPress import.
- There is no `load_plugin_textdomain()` call: the plugin is hosted on
WordPress.org and requires WordPress 6.0, so WordPress auto-loads the
GlotPress language packs from `WP_LANG_DIR` (WordPress 4.6+ behavior);
see
[How to internationalize your plugin](https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plugins-on-wordpress-org).
- `languages/mikesoft-teamvault.pot` is the translatable-string template,
generated with WP-CLI and shipped for GlotPress import.
- The hardcoded it/fr/es/de maps in `includes/class-mstv-i18n.php` stay as a
**runtime fallback** (via the `gettext` filter) so the bundled interface
languages keep working when no language pack is installed. They are not the
translation source of truth — GlotPress is.
- Precedence: an installed language pack always wins over the bundled map, so
the "Interface language" setting selects the fallback only and cannot
override a locale that ships a pack. This is deliberate (GlotPress
translations are reviewed by locale editors) and covered by
`tests/PDMI18nRuntimeTest.php`. Forcing a different locale on sites that do
have a pack would need a `plugin_locale` filter, which is not implemented.

## Regenerating the POT

Preferred (requires wp-cli):

```sh
wp i18n make-pot . languages/mikesoft-teamvault.pot --domain=mikesoft-teamvault
```

The committed POT was produced with an equivalent extractor (same function
set and `mikesoft-teamvault` domain filter, `#: file:line` references,
`Plural-Forms: nplurals=2; plural=(n != 1);`) because wp-cli was unavailable;
re-running `wp i18n make-pot` is welcome to normalize it.
The command runs in the plugin directory without a WordPress installation.
The committed POT is the raw WP-CLI output: plugin header metadata,
`#: file:line` references, `#. translators:` comments, and `#, php-format`
flags for strings with placeholders. Regenerate it whenever user-facing
strings change, and before a release, so translators see the current set with
correct references.

## GlotPress handoff

1. Import the updated `.pot` into the
[WordPress.org plugin GlotPress project](https://translate.wordpress.org/projects/wp-plugins/mikesoft-teamvault/)
on release.
1. Release the plugin. WordPress.org extracts the strings from the released
plugin, so the
[plugin GlotPress project](https://translate.wordpress.org/projects/wp-plugins/mikesoft-teamvault/)
updates on its own; import the committed `.pot` manually only when a
refresh is needed.
2. Approved translations ship automatically as WordPress.org language packs
into `wp-content/languages/plugins/` — no bundled `.po`/`.mo` files needed.
3. Keep the fallback maps in sync only until GlotPress coverage for a locale
is complete; the maps must always cover every `mikesoft-teamvault` string
(guarded by `tests/PdmI18nCoverageTest.php`).
into `wp-content/languages/plugins/` — no bundled `.po`/`.mo` files
needed.
3. Keep the fallback maps in sync until GlotPress coverage for a locale is
complete; the maps must always cover every `mikesoft-teamvault` string
(guarded by `tests/PdmI18nCoverageTest.php`, and the pack-over-map
precedence by `tests/PDMI18nRuntimeTest.php`).

## Terminology

Decisions to keep the bundled locales internally consistent:

- "Vault" names the TeamVault workspace. Italian, Spanish, and German keep the
English word; French uses "coffre". Do not mix the two forms inside one
locale.
- Italian renders "storage" as "archiviazione" everywhere, including labels
such as "Directory di archiviazione" and "Reindicizza archiviazione".
- Italian uses "elenco" (not "lista") and "Gestione file" for the File Manager
screen.
- Event labels follow the WordPress Italian convention: "upload" is
"caricamento", "download" stays "download".
23 changes: 13 additions & 10 deletions docs/maintainer/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@ The deploy script already validates plugin version and stable tag alignment.
2. Update `Stable tag` and the current release entry in `readme.txt`.
3. Add the full release entry to `changelog.txt`.
4. Update the current plugin version and latest release summary in every localized `README*.md`.
5. Run `composer validate --strict`, `composer audit --locked`, and `composer ci` from `mikesoft-teamvault-src/`.
6. Run the JavaScript syntax checks and `node --test tests/plugin-check-output.test.mjs`.
7. Run `Invoke-Pester .\deployment\DeployWordPressOrg.Tests.ps1` from the workspace root.
8. Run WordPress Plugin Check against the clean runtime payload.
9. Smoke test the file browser REST endpoint with plain permalinks when REST URL handling changes.
10. Confirm `.wordpress-org/assets/` contains the expected public assets.
11. Build the release ZIP and verify that repository-only files and sensitive local files are absent.
12. Commit the release on a maintainer branch, open an internal pull request, wait for required CI and CodeQL checks, merge into protected `main`, and publish the matching GitHub tag and release with the ZIP attached.
13. Run the WordPress.org deployment script from the workspace root.
14. Verify the public GitHub release and the WordPress.org `trunk` and version tag.
5. If user-facing strings changed, regenerate `languages/mikesoft-teamvault.pot` with `wp i18n make-pot` (see `docs/developer/i18n.md`).
6. Run `composer validate --strict`, `composer audit --locked`, and `composer ci` from `mikesoft-teamvault-src/`.
7. Run the JavaScript syntax checks and `node --test tests/plugin-check-output.test.mjs`.
8. Run `Invoke-Pester .\deployment\DeployWordPressOrg.Tests.ps1` from the workspace root.
9. Run WordPress Plugin Check against the clean runtime payload.
10. Smoke test the file browser REST endpoint with plain permalinks when REST URL handling changes.
11. Confirm `.wordpress-org/assets/` contains the expected public assets.
12. Build the release ZIP and verify that repository-only files and sensitive local files are absent.
13. Commit the release on a maintainer branch, open an internal pull request, wait for required CI and CodeQL checks, merge into protected `main`, and publish the matching GitHub tag and release with the ZIP attached.
14. Run the WordPress.org deployment script from the workspace root.
15. Verify the public GitHub release and the WordPress.org `trunk` and version tag.

## Changelog Policy

Expand All @@ -53,6 +54,8 @@ Keep the shipped `readme.txt` in English. WordPress.org localizes plugin listing

For Italian listing copy, translate the plugin readme strings in the plugin's Development Readme project on translate.wordpress.org and wait for locale validation.

Interface translations are handled separately: the bundled fallback maps, the POT workflow, and the pack-over-map precedence are documented in `docs/developer/i18n.md`.

## Deployment Command

From the workspace root:
Expand Down
6 changes: 5 additions & 1 deletion includes/class-mstv-helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ public static function human_time_diff_mysql(string $mysqlTime): string
if ($time === false) {
return '';
}
return human_time_diff($time, time()) . ' ' . __('ago', 'mikesoft-teamvault');
return sprintf(
/* translators: %s: time elapsed, for example "5 mins". */
__('%s ago', 'mikesoft-teamvault'),
human_time_diff($time, time())
);
}

public static function build_breadcrumb(array $folders, int $currentFolderId): array
Expand Down
Loading
Loading