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
30 changes: 30 additions & 0 deletions docs/API-Reference/command/Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,18 @@ Zooms out the editor view
## VIEW\_ZOOM\_SUBMENU
Submenu for zoom options

**Kind**: global variable
<a name="OPEN_IN_SUBMENU"></a>

## OPEN\_IN\_SUBMENU
Submenu for Open in project context menu

**Kind**: global variable
<a name="OPEN_IN_SUBMENU_WS"></a>

## OPEN\_IN\_SUBMENU\_WS
Submenu for Open in working set context menu

**Kind**: global variable
<a name="VIEW_INCREASE_FONT_SIZE"></a>

Expand Down Expand Up @@ -602,6 +614,24 @@ Shows current file in file tree
## NAVIGATE\_SHOW\_IN\_OS
Shows current file in OS file explorer

**Kind**: global variable
<a name="NAVIGATE_OPEN_IN_TERMINAL"></a>

## NAVIGATE\_OPEN\_IN\_TERMINAL
Shows current file in OS Terminal

**Kind**: global variable
<a name="NAVIGATE_OPEN_IN_POWERSHELL"></a>

## NAVIGATE\_OPEN\_IN\_POWERSHELL
Shows current file in open powershell in Windows os

**Kind**: global variable
<a name="NAVIGATE_OPEN_IN_DEFAULT_APP"></a>

## NAVIGATE\_OPEN\_IN\_DEFAULT\_APP
Open current file in the default associated app in the os

**Kind**: global variable
<a name="NAVIGATE_QUICK_OPEN"></a>

Expand Down
63 changes: 63 additions & 0 deletions docs/API-Reference/utils/LocalizationUtils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
### Import :
```js
const LocalizationUtils = brackets.getModule("utils/LocalizationUtils")
```

<a name="getLocalizedLabel"></a>

## getLocalizedLabel(locale) ⇒ <code>string</code>
Converts a language code to its written name, if possible.
If not possible, the language code is simply returned.

**Kind**: global function
**Returns**: <code>string</code> - The language's name or the given language code

| Param | Type | Description |
| --- | --- | --- |
| locale | <code>string</code> | The two-char language code |

<a name="getFormattedDateTime"></a>

## getFormattedDateTime([date], [lang], [dateTimeFormat]) ⇒ <code>string</code>
Formats a given date object into a locale-aware date and time string.

**Kind**: global function
**Returns**: <code>string</code> - - The formatted date and time string (e.g., "Dec 24, 2024, 10:30 AM").

| Param | Type | Description |
| --- | --- | --- |
| [date] | <code>Date</code> | The date object to format. If not provided, the current date and time will be used. |
| [lang] | <code>string</code> | Optional language code to use for formatting (e.g., 'en', 'fr'). If not provided, defaults to the application locale or 'en'. |
| [dateTimeFormat] | <code>Object</code> | Optional object specifying the date and time formatting options. Defaults to { dateStyle: 'medium', timeStyle: 'short' }. |
| [dateTimeFormat.dateStyle] | <code>string</code> | Specifies the date format style. One of: DATE_TIME_STYLE.* |
| [dateTimeFormat.timeStyle] | <code>string</code> | Specifies the time format style. One of: DATE_TIME_STYLE.* |

<a name="dateTimeFromNow"></a>

## dateTimeFromNow([date], [lang]) ⇒ <code>string</code>
Returns a relative time string (e.g., "2 days ago", "in 3 hours") based on the difference between the given date and now.

**Kind**: global function
**Returns**: <code>string</code> - - A human-readable relative time string (e.g., "2 days ago", "in 3 hours").

| Param | Type | Description |
| --- | --- | --- |
| [date] | <code>Date</code> | The date to compare with the current date and time. If not given, defaults to now. |
| [lang] | <code>string</code> | Optional language code to use for formatting (e.g., 'en', 'fr'). If not provided, defaults to the application locale or 'en'. |

<a name="dateTimeFromNowFriendly"></a>

## dateTimeFromNowFriendly(date, [lang]) ⇒ <code>string</code>
Returns an intelligent date string.
- For dates within the last 30 days or the future: relative time (e.g., "2 days ago", "in 3 hours").
- For dates earlier this year: formatted date (e.g., "Jan 5").
- For dates not in the current year: formatted date with year (e.g., "Jan 5, 2023").

**Kind**: global function
**Returns**: <code>string</code> - - An intelligently formatted date string.

| Param | Type | Description |
| --- | --- | --- |
| date | <code>Date</code> | The date to compare and format. |
| [lang] | <code>string</code> | Optional language code to use for formatting (e.g., 'en', 'fr'). |

25 changes: 25 additions & 0 deletions docs/API-Reference/utils/NodeUtils.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,28 @@ This is only available in the native app
| fullFilePath | <code>string</code> |
| projectFullPath | <code>string</code> |

<a name="openNativeTerminal"></a>

## openNativeTerminal(cwd, [usePowerShell])
Runs ESLint on a file
This is only available in the native app

**Kind**: global function

| Param | Type | Default | Description |
| --- | --- | --- | --- |
| cwd | <code>string</code> | | the working directory of terminal |
| [usePowerShell] | <code>boolean</code> | <code>false</code> | |

<a name="openInDefaultApp"></a>

## openInDefaultApp(fullPath) ⇒ <code>Promise.&lt;void&gt;</code>
Opens a file in the default application for its type on Windows, macOS, and Linux.

**Kind**: global function
**Returns**: <code>Promise.&lt;void&gt;</code> - - Resolves if the file/folder is opened successfully, rejects otherwise.

| Param | Type | Description |
| --- | --- | --- |
| fullPath | <code>string</code> | The path to the file/folder to open. |

3 changes: 2 additions & 1 deletion docs/API-Reference/widgets/PopUpManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ Add Esc key handling for a popup DOM element.
| removeHandler | <code>function</code> | Pop-up specific remove (e.g. display:none or DOM removal) |
| autoRemove | <code>Boolean</code> | Specify true to indicate the PopUpManager should remove the popup from the _popUps array when the popup is closed. Specify false when the popup is always persistant in the _popUps array. |
| options | <code>object</code> | |
| options.popupManagesFocus | <code>boolean</code> | set to true if the popup manages focus restore on close |
| [options.popupManagesFocus] | <code>boolean</code> | set to true if the popup manages focus restore on close |
| [options.closeCurrentPopups] | <code>boolean</code> | set to true if you want to dismiss all exiting popups before adding this. Useful when this should be the only popup visible. |

<a name="removePopUp"></a>

Expand Down
1 change: 1 addition & 0 deletions src/brackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ define(function (require, exports, module) {
require("language/JSONUtils");
require("widgets/InlineMenu");
require("thirdparty/tinycolor");
require("utils/LocalizationUtils");

// DEPRECATED: In future we want to remove the global CodeMirror, but for now we
// expose our required CodeMirror globally so as to avoid breaking extensions in the
Expand Down
112 changes: 106 additions & 6 deletions src/utils/LocalizationUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@
*
*/

/**
* Utilities functions related to localization/i18n
*/
define(function (require, exports, module) {
// @INCLUDE_IN_API_DOCS

define(function (require, exports, module) {

var Strings = require("strings");
const Strings = require("strings");

/*
/**
* Converts a language code to its written name, if possible.
* If not possible, the language code is simply returned.
*
Expand All @@ -41,7 +39,109 @@ define(function (require, exports, module) {
return i18n === undefined ? locale : i18n;
}

const DATE_TIME_STYLE = {
FULL: "full",
LONG: "long",
MEDIUM: "medium",
SHORT: "short"
};

/**
* Formats a given date object into a locale-aware date and time string.
*
* @param {Date} [date] - The date object to format. If not provided, the current date and time will be used.
* @param {string} [lang] - Optional language code to use for formatting (e.g., 'en', 'fr').
* If not provided, defaults to the application locale or 'en'.
* @param {Object} [dateTimeFormat] - Optional object specifying the date and time formatting options.
* Defaults to { dateStyle: 'medium', timeStyle: 'short' }.
* @param {string} [dateTimeFormat.dateStyle] - Specifies the date format style. One of: DATE_TIME_STYLE.*
* @param {string} [dateTimeFormat.timeStyle] - Specifies the time format style. One of: DATE_TIME_STYLE.*
* @returns {string} - The formatted date and time string (e.g., "Dec 24, 2024, 10:30 AM").
*/
function getFormattedDateTime(date, lang, dateTimeFormat) {
if(!date){
date = new Date();
}
if(!dateTimeFormat){
dateTimeFormat = {
dateStyle: DATE_TIME_STYLE.MEDIUM,
timeStyle: DATE_TIME_STYLE.SHORT
};
}
return Intl.DateTimeFormat([lang || brackets.getLocale() || "en", "en"], dateTimeFormat).format(date);
}

/**
* Returns a relative time string (e.g., "2 days ago", "in 3 hours") based on the difference between the given date and now.
*
* @param {Date} [date] - The date to compare with the current date and time. If not given, defaults to now.
* @param {string} [lang] - Optional language code to use for formatting (e.g., 'en', 'fr').
* If not provided, defaults to the application locale or 'en'.
* @returns {string} - A human-readable relative time string (e.g., "2 days ago", "in 3 hours").
*/
function dateTimeFromNow(date, lang) {
date = date || new Date();
const now = new Date();
const diffInSeconds = Math.floor((date - now) / 1000);

const rtf = new Intl.RelativeTimeFormat([lang || brackets.getLocale() || "en", "en"],
{ numeric: 'auto' });

if (Math.abs(diffInSeconds) < 60) {
return rtf.format(diffInSeconds, 'second');
} else if (Math.abs(diffInSeconds) < 3600) {
return rtf.format(Math.floor(diffInSeconds / 60), 'minute');
} else if (Math.abs(diffInSeconds) < 86400) {
return rtf.format(Math.floor(diffInSeconds / 3600), 'hour');
} else if (Math.abs(diffInSeconds) < 2592000) {
return rtf.format(Math.floor(diffInSeconds / 86400), 'day');
} else if (Math.abs(diffInSeconds) < 31536000) {
return rtf.format(Math.floor(diffInSeconds / 2592000), 'month');
} else {
return rtf.format(Math.floor(diffInSeconds / 31536000), 'year');
}
}

/**
* Returns an intelligent date string.
* - For dates within the last 30 days or the future: relative time (e.g., "2 days ago", "in 3 hours").
* - For dates earlier this year: formatted date (e.g., "Jan 5").
* - For dates not in the current year: formatted date with year (e.g., "Jan 5, 2023").
*
* @param {Date} date - The date to compare and format.
* @param {string} [lang] - Optional language code to use for formatting (e.g., 'en', 'fr').
* @returns {string} - An intelligently formatted date string.
*/
function dateTimeFromNowFriendly(date, lang) {
const now = new Date();
const diffInMilliseconds = date - now;
const diffInDays = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24));

// If within the last 30 days or the future, use relative time
if (Math.abs(diffInDays) <= 30) {
return dateTimeFromNow(date, lang);
}

// If in the current year, format as "MMM DD"
const currentYear = now.getFullYear();
const dateYear = date.getFullYear();

const languageOption = [lang || brackets.getLocale() || "en", "en"];

if (currentYear === dateYear) {
return new Intl.DateTimeFormat(languageOption, { month: "short", day: "numeric" }).format(date);
}

// For dates in previous years, format as "MMM DD, YYYY"
return new Intl.DateTimeFormat(languageOption,
{ month: "short", day: "numeric", year: "numeric" }).format(date);
}

// Define public API
exports.getLocalizedLabel = getLocalizedLabel;
exports.getFormattedDateTime = getFormattedDateTime;
exports.dateTimeFromNow = dateTimeFromNow;
exports.dateTimeFromNowFriendly = dateTimeFromNowFriendly;
// public constants
exports.DATE_TIME_STYLE = DATE_TIME_STYLE;
});
1 change: 1 addition & 0 deletions test/UnitTestSuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ define(function (require, exports, module) {
require("spec/TaskManager-integ-test");
require("spec/Generic-integ-test");
require("spec/spacing-auto-detect-integ-test");
require("spec/LocalizationUtils-test");
// Integrated extension tests
require("spec/Extn-InAppNotifications-integ-test");
require("spec/Extn-RemoteFileAdapter-integ-test");
Expand Down
Loading
Loading