diff --git a/.changeset/early-years-jog.md b/.changeset/early-years-jog.md new file mode 100644 index 0000000000..c0fff52899 --- /dev/null +++ b/.changeset/early-years-jog.md @@ -0,0 +1,31 @@ +--- +"@hashicorp/design-system-components": minor +--- + +- Added `ember-intl` as a dependency +- Added `hdsIntl` service for translations with default fallback values +- Added `hds-t` helper which uses the `hds-intl` service to provide translations in templates + +`AdvancedTable` - Translated template strings. Removed extraneous screen-reader-only text. + +`AppFooter` - Translated template strings + +`AppSideNav` - Translated template strings + +`ApplicationState` - Translated template strings + +`CodeEditor` - Translated template strings + +`DismissButton` - Translated template strings + +`MaskedInput` - Translated template strings + +`SuperSelect` - Translated template strings + +`Pagination` - Translated template strings + +`SideNav` - Translated template strings + +`Table` - Translated template strings + +`Time` - Translated template strings diff --git a/packages/components/.template-lintrc.cjs b/packages/components/.template-lintrc.cjs index 61071fc7b8..1516aab7fb 100644 --- a/packages/components/.template-lintrc.cjs +++ b/packages/components/.template-lintrc.cjs @@ -13,5 +13,6 @@ module.exports = { 'no-unnecessary-curly-strings': false, 'no-redundant-role': false, 'no-builtin-form-components': false, + 'no-bare-strings': true, }, }; diff --git a/packages/components/config/ember-intl.mjs b/packages/components/config/ember-intl.mjs new file mode 100644 index 0000000000..d7dc5933ea --- /dev/null +++ b/packages/components/config/ember-intl.mjs @@ -0,0 +1,95 @@ +'use strict'; + +module.exports = function (/* environment */) { + return { + /** + * Cause a build error if missing translations are detected. + * + * See https://ember-intl.github.io/ember-intl/docs/guide/missing-translations#throwing-a-build-error-on-missing-when-required-translations + * + * @property errorOnMissingTranslations + * @type {Boolean} + * @default "false" + */ + errorOnMissingTranslations: false, + + /** + * Cause a build error if ICU argument mismatches are detected between translations + * with the same key across all locales. + * + * @property errorOnNamedArgumentMismatch + * @type {Boolean} + * @default "false" + */ + errorOnNamedArgumentMismatch: false, + + /** + * Merges the fallback locale's translations into all other locales as a + * build-time fallback strategy. + * + * This will **not** prevent missing translation warnings or errors from occurring. + * It's meant as safety net when warnings are enabled. + * When enabled along with `errorOnMissingTranslations` any fallback attempts will result in an error. + * + * @property fallbackLocale + * @type {String?} + * @default "null" + */ + fallbackLocale: null, + + /** + * Path where translations are stored. This is relative to the project root. + * For example, if your translations are an npm dependency, set this to: + *`'./node_modules/path/to/translations'` + * + * @property inputPath + * @type {String} + * @default "'translations'" + */ + inputPath: 'translations', + + /** + * Prevents the translations from being bundled with the application code. + * This enables asynchronously loading the translations for the active locale + * by fetching them from the asset folder of the build. + * + * See: https://ember-intl.github.io/ember-intl/docs/guide/asynchronously-loading-translations + * + * @property publicOnly + * @type {Boolean} + * @default "false" + */ + publicOnly: false, + + /** + * A function that is called whenever any translation key, from any locale, is missing at build time. + * + * See https://ember-intl.github.io/ember-intl/docs/guide/missing-translations#requiring-translations + * + * @property requiresTranslation + * @type {Function} + * @default "function(key,locale) { return true }" + */ + requiresTranslation(/* key, locale */) { + return true; + }, + + /** + * Removes empty translations from the build output. + * + * @property stripEmptyTranslations + * @type {Boolean} + * @default "false" + */ + stripEmptyTranslations: false, + + /** + * Add the subdirectories of the translations as a namespace for all keys. + * + * @property wrapTranslationsWithNamespace + * @type {Boolean} + * @default "false" + */ + wrapTranslationsWithNamespace: true, + }; +}; diff --git a/packages/components/package.json b/packages/components/package.json index 8185ea3313..b10655c113 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -96,6 +96,7 @@ "babel-plugin-ember-template-compilation": "^2.4.1", "concurrently": "^9.1.2", "ember-basic-dropdown": "^8.6.1", + "ember-intl": "^7.3.0", "ember-source": "^6.4.0", "ember-template-lint": "^7.0.2", "ember-template-lint-plugin-prettier": "^5.0.0", @@ -119,11 +120,15 @@ "webpack": "^5.97.1" }, "peerDependencies": { - "ember-engines": ">= 0.11.0" + "ember-engines": ">= 0.11.0", + "ember-intl": "^7.3.0" }, "peerDependenciesMeta": { "ember-engines": { "optional": true + }, + "ember-intl": { + "optional": true } }, "ember": { @@ -349,6 +354,7 @@ "./helpers/hds-format-relative.js": "./dist/_app_/helpers/hds-format-relative.js", "./helpers/hds-link-to-models.js": "./dist/_app_/helpers/hds-link-to-models.js", "./helpers/hds-link-to-query.js": "./dist/_app_/helpers/hds-link-to-query.js", + "./helpers/hds-t.js": "./dist/_app_/helpers/hds-t.js", "./instance-initializers/load-sprite.js": "./dist/_app_/instance-initializers/load-sprite.js", "./modifiers/hds-advanced-table-cell.js": "./dist/_app_/modifiers/hds-advanced-table-cell.js", "./modifiers/hds-advanced-table-cell/dom-management.js": "./dist/_app_/modifiers/hds-advanced-table-cell/dom-management.js", @@ -365,6 +371,7 @@ "./modifiers/hds-code-editor/types.js": "./dist/_app_/modifiers/hds-code-editor/types.js", "./modifiers/hds-register-event.js": "./dist/_app_/modifiers/hds-register-event.js", "./modifiers/hds-tooltip.js": "./dist/_app_/modifiers/hds-tooltip.js", + "./services/hds-intl.js": "./dist/_app_/services/hds-intl.js", "./services/hds-time.js": "./dist/_app_/services/hds-time.js" } }, @@ -389,7 +396,8 @@ "files": [ "addon-main.cjs", "declarations", - "dist" + "dist", + "translations" ], "engines": { "node": ">= 18" diff --git a/packages/components/src/components/hds/advanced-table/th-button-expand.hbs b/packages/components/src/components/hds/advanced-table/th-button-expand.hbs index 7a202a86d5..d5472da3b8 100644 --- a/packages/components/src/components/hds/advanced-table/th-button-expand.hbs +++ b/packages/components/src/components/hds/advanced-table/th-button-expand.hbs @@ -10,10 +10,15 @@ {{on "click" this.onClick}} aria-labelledby="{{this._prefixLabelId}} {{@labelId}}" aria-expanded="{{this.isExpanded}}" - aria-description="Toggle the visibility of the related rows." + aria-description={{hds-t + "hds.components.advanced-table.th-button-expand.aria-description" + default="Toggle the visibility of the related rows." + }} ...attributes > {{! template-lint-enable no-unsupported-role-attributes}} - Toggle + + {{hds-t "hds.components.common.toggle" default="Toggle"}} + \ No newline at end of file diff --git a/packages/components/src/components/hds/advanced-table/th-button-sort.hbs b/packages/components/src/components/hds/advanced-table/th-button-sort.hbs index b99c1e41dd..d5b1e131eb 100644 --- a/packages/components/src/components/hds/advanced-table/th-button-sort.hbs +++ b/packages/components/src/components/hds/advanced-table/th-button-sort.hbs @@ -9,7 +9,9 @@ aria-labelledby="{{this._prefixLabelId}} {{@labelId}} {{this._suffixLabelId}}" ...attributes > - Sort by + + {{hds-t "hds.components.common.sort-by" default="Sort by"}} + - More information for + + {{hds-t "hds.components.common.tooltip-prefix" default="More information for"}} + \ No newline at end of file diff --git a/packages/components/src/components/hds/advanced-table/th-selectable.hbs b/packages/components/src/components/hds/advanced-table/th-selectable.hbs index c2888658fd..fcc89bff95 100644 --- a/packages/components/src/components/hds/advanced-table/th-selectable.hbs +++ b/packages/components/src/components/hds/advanced-table/th-selectable.hbs @@ -21,7 +21,6 @@ {{on "change" this.onSelectionChange}} /> {{#if this.isSortable}} - selection state - © {{this.year}} HashiCorp + + {{hds-t + "hds.components.app-footer.copyright.copyright-text" + default=(concat "© " this.year " HashiCorp") + year=this.year + }} + \ No newline at end of file diff --git a/packages/components/src/components/hds/app-footer/legal-links.hbs b/packages/components/src/components/hds/app-footer/legal-links.hbs index ee0169e96d..5023e1efe5 100644 --- a/packages/components/src/components/hds/app-footer/legal-links.hbs +++ b/packages/components/src/components/hds/app-footer/legal-links.hbs @@ -5,10 +5,20 @@ \ No newline at end of file diff --git a/packages/components/src/components/hds/app-header/menu-button.hbs b/packages/components/src/components/hds/app-header/menu-button.hbs index 0629c99bb4..3109076586 100644 --- a/packages/components/src/components/hds/app-header/menu-button.hbs +++ b/packages/components/src/components/hds/app-header/menu-button.hbs @@ -5,7 +5,7 @@ -

Application local navigation

+

+ {{hds-t "hds.components.app-side-nav.heading" default="Application local navigation"}} +

{{#if this.showToggleButton}} diff --git a/packages/components/src/components/hds/application-state/header.hbs b/packages/components/src/components/hds/application-state/header.hbs index ca6e31581a..a5f96b3bf6 100644 --- a/packages/components/src/components/hds/application-state/header.hbs +++ b/packages/components/src/components/hds/application-state/header.hbs @@ -5,7 +5,7 @@
{{#if @errorCode}} - ERROR + {{hds-t "hds.components.common.error" default="Error"}} {{@errorCode}} {{/if}} diff --git a/packages/components/src/components/hds/code-editor/full-screen-button.hbs b/packages/components/src/components/hds/code-editor/full-screen-button.hbs index d2dd892b7b..92c5c29df0 100644 --- a/packages/components/src/components/hds/code-editor/full-screen-button.hbs +++ b/packages/components/src/components/hds/code-editor/full-screen-button.hbs @@ -10,7 +10,7 @@ @color="secondary" @size="small" @icon={{this.state}} - @text="Toggle full screen view" + @text={{hds-t "hds.components.code-editor.full-screen-button.text" default="Toggle full screen view"}} {{on "click" @onToggleFullScreen}} ...attributes /> \ No newline at end of file diff --git a/packages/components/src/components/hds/code-editor/index.hbs b/packages/components/src/components/hds/code-editor/index.hbs index a02fd8d599..9eecf641a7 100644 --- a/packages/components/src/components/hds/code-editor/index.hbs +++ b/packages/components/src/components/hds/code-editor/index.hbs @@ -71,7 +71,7 @@ {{#unless this._isSetupComplete}}
- Loading + {{hds-t "hds.components.common.loading" default="Loading"}}
{{/unless}}
\ No newline at end of file diff --git a/packages/components/src/components/hds/dismiss-button/index.ts b/packages/components/src/components/hds/dismiss-button/index.ts index e37acdadfc..ad38ff511c 100644 --- a/packages/components/src/components/hds/dismiss-button/index.ts +++ b/packages/components/src/components/hds/dismiss-button/index.ts @@ -4,6 +4,9 @@ */ import Component from '@glimmer/component'; +import { service } from '@ember/service'; + +import type HdsIntlService from '../../../services/hds-intl'; export interface HdsDismissButtonSignature { Args: { @@ -13,12 +16,14 @@ export interface HdsDismissButtonSignature { } export default class HdsDismissButton extends Component { - /** - * @param ariaLabel - * @type {string} - * @default 'Dismiss' - */ + @service hdsIntl!: HdsIntlService; + get ariaLabel(): string { - return this.args.ariaLabel ?? 'Dismiss'; + return ( + this.args.ariaLabel ?? + this.hdsIntl.t('hds.components.dismiss-button.aria-label', { + default: 'Dismiss', + }) + ); } } diff --git a/packages/components/src/components/hds/form/indicator/index.hbs b/packages/components/src/components/hds/form/indicator/index.hbs index 4002c85634..f474506f96 100644 --- a/packages/components/src/components/hds/form/indicator/index.hbs +++ b/packages/components/src/components/hds/form/indicator/index.hbs @@ -3,8 +3,16 @@ SPDX-License-Identifier: MPL-2.0 }} {{#if @isOptional}} - (Optional) + + ({{hds-t "hds.components.form.common.optional_field_indicator" default="Optional"}}) + {{/if}} {{#if @isRequired}} -