diff --git a/OAT.xml b/OAT.xml index 9705a1cbe38d1ac277d21d688189b738b49a37d6..79ead97564866e6d5272597ac61b72ce1092936f 100644 --- a/OAT.xml +++ b/OAT.xml @@ -1346,6 +1346,10 @@ Note:If the text contains special characters, please escape them according to th + + + + @@ -1472,6 +1476,66 @@ Note:If the text contains special characters, please escape them according to th + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/BasicFeature/TaskManagement/ReminderAgentManager/entry/src/main/ets/util/CalendarReminder.ets b/code/BasicFeature/TaskManagement/ReminderAgentManager/entry/src/main/ets/util/CalendarReminder.ets index 5c27a781ef08a37962f36a208bb3b296a92ea01d..4920c60736e2811e452e18232b504a168ac1cdc9 100644 --- a/code/BasicFeature/TaskManagement/ReminderAgentManager/entry/src/main/ets/util/CalendarReminder.ets +++ b/code/BasicFeature/TaskManagement/ReminderAgentManager/entry/src/main/ets/util/CalendarReminder.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,13 +14,13 @@ */ import reminderAgent from '@ohos.reminderAgentManager'; -import vibrator from '@ohos.vibrator' -import AudioPlayer from './AudioPlayer' -import Constant from '../common/Constant' -import Logger from './Logger' -import PreferencesDataManager from './PreferencesDataManager' -import { Reminder } from '../common/Reminder' -import TimeConversion from './TimeConversion' +import vibrator from '@ohos.vibrator'; +import AudioPlayer from './AudioPlayer'; +import Constant from '../common/Constant'; +import Logger from './Logger'; +import PreferencesDataManager from './PreferencesDataManager'; +import { Reminder } from '../common/Reminder'; +import TimeConversion from './TimeConversion'; import common from '@ohos.app.ability.common'; import notificationManager from '@ohos.notificationManager'; import { BusinessError, deviceInfo } from '@kit.BasicServicesKit'; @@ -30,10 +30,10 @@ import { promptAction } from '@kit.ArkUI'; let deviceTypeInfo: string = deviceInfo.deviceType; let calendar: calendarManager.Calendar | undefined = undefined; -const TAG: string = 'CalendarReminder' +const TAG: string = 'CalendarReminder'; class CalendarReminder { - public calendarReminders: Reminder[] = [] + public calendarReminders: Reminder[] = []; setCalendarReminder() { let config: calendarManager.CalendarConfig = { @@ -60,8 +60,8 @@ class CalendarReminder { let month = date.month! < 9 ? `0${date.month! + 1}` : `${date.month! + 1}`; let day = date.day! < 10 ? `0${date.day}` : date.day; let context = getContext(this) as common.UIAbilityContext; - let selectCalendar: string = `${date.year}-${month}-${day}` - let isExistName = this.calendarReminders.find(element => element.reminderName === selectCalendar) !== undefined + let selectCalendar: string = `${date.year}-${month}-${day}`; + let isExistName = this.calendarReminders.find(element => element.reminderName === selectCalendar) !== undefined; if (!isExistName) { let reminder: Reminder = { audioSrc: '', @@ -95,11 +95,11 @@ class CalendarReminder { content: context.resourceManager.getStringSync($r('app.string.calendar_reach').id), slotType: notificationManager.SlotType.CONTENT_INFORMATION } - Logger.info(TAG, `setCalendar this calendar is ${JSON.stringify(calendar)}}`) + Logger.info(TAG, `setCalendar this calendar is ${JSON.stringify(calendar)}}`); reminder.reminderRequestCalendar = calendar reminder.isStart = false this.calendarReminders.push(reminder) - Logger.info(TAG, `setCalendar this all calendar is ${JSON.stringify(this.calendarReminders)}`) + Logger.info(TAG, `setCalendar this all calendar is ${JSON.stringify(this.calendarReminders)}`); await PreferencesDataManager.putData('Calendar', this.calendarReminders) this.setCalendarReminder(); } else { @@ -120,10 +120,9 @@ class CalendarReminder { this.calendarReminders[index].reminderId = reminderId; } else { let context = getContext(this) as common.UIAbilityContext; - let date = new Date(); - let year = date.getFullYear(); - let month = date.getMonth() + 1; - let day = date.getDate(); + let year = this.calendarReminders[index].reminderRequestCalendar!.dateTime.year; + let month = this.calendarReminders[index].reminderRequestCalendar!.dateTime.month; + let day = this.calendarReminders[index].reminderRequestCalendar!.dateTime.day; let dateHour = this.calendarReminders[index].reminderRequestCalendar!.dateTime.hour; let dateMinute = this.calendarReminders[index].reminderRequestCalendar!.dateTime.minute; let hour = dateHour < 10 ? `0${dateHour}` : dateHour; @@ -156,7 +155,7 @@ class CalendarReminder { this.calendarReminders[index].reminderRequestCalendar!.dateTime.day, this.calendarReminders[index].reminderRequestCalendar!.dateTime.hour, this.calendarReminders[index].reminderRequestCalendar!.dateTime.minute) * Constant.SECONDS_MILLISECONDS); - this.calendarReminders[index].audioTimeouts = audioIndex; + this.calendarReminders[index].audioTimeouts = audioIndex; } await PreferencesDataManager.putData('Calendar', this.calendarReminders) if (this.calendarReminders[index].isVibrator) { @@ -171,9 +170,9 @@ class CalendarReminder { usage: 'alarm' }, (err) => { if (err) { - Logger.error(TAG, `setToggle this vibrator is failed err is ${JSON.stringify(err)}`) + Logger.error(TAG, `setToggle this vibrator is failed err is ${JSON.stringify(err)}`); } else { - Logger.info(TAG, `setToggle this vibrator is successed`) + Logger.info(TAG, `setToggle this vibrator is successed`); } }) }, TimeConversion.dateToMillisecond(this.calendarReminders[index].reminderRequestCalendar!.dateTime.year, diff --git a/code/DocsSample/International/Internationalization/.gitignore b/code/DocsSample/International/Internationalization/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/code/DocsSample/International/Internationalization/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/AppScope/app.json5 b/code/DocsSample/International/Internationalization/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..789ce3dec92fed62e2d085120c42a1f787485a95 --- /dev/null +++ b/code/DocsSample/International/Internationalization/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "bundleName": "com.samples.internationalization", + "vendor": "sample", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/code/DocsSample/International/Internationalization/AppScope/resources/base/element/string.json b/code/DocsSample/International/Internationalization/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..999cd2ffc592f588885f354853a12461aa7f682b --- /dev/null +++ b/code/DocsSample/International/Internationalization/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "Internationalization" + } + ] +} diff --git a/code/DocsSample/International/Internationalization/AppScope/resources/base/media/app_icon.png b/code/DocsSample/International/Internationalization/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/code/DocsSample/International/Internationalization/AppScope/resources/base/media/app_icon.png differ diff --git a/code/DocsSample/International/Internationalization/README_zh.md b/code/DocsSample/International/Internationalization/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..e037c2c5b5180876b0106bce5fd871192d95e077 --- /dev/null +++ b/code/DocsSample/International/Internationalization/README_zh.md @@ -0,0 +1,90 @@ +# 国际化Internationalization + +## 介绍 + +本示例依照指南 开发->应用框架->Localization Kit(本地化开发服务)->[本地化开发服务(应用国际化)](https://gitee.com/openharmony/docs/tree/OpenHarmony-5.0.1-Release/zh-cn/application-dev/internationalization)进行编写。 +本示例主要展示了国际化的相关基础功能,通过调用`intl`,`i18n`实现简单的国际化操作。 + +### 效果预览 + +| **主页面** | **区域标识与文化习惯划分界面** | **设置日历和历法界面** | **时间日期国际化界面** | +| ------------------------------------- | ------------------------------------------------------------ | --------------------------------------------------- | --------------------------------------------------------- | +| ![MainPage](./screenshots/MainPage.jpg) | ![LocaleCulturalDivision](./screenshots/LocaleCulturalDivision.jpg) | ![CalendarSetting](./screenshots/CalendarSetting.jpg) | ![DateTimeFormatting](./screenshots/DateTimeFormatting.jpg) | + +使用说明: + +1. 修改HarmonyAppProvision配置文件为system_basic等级系统应用。 +2. 启动应用,进入主页面。 +3. 点击主页面不同的功能按钮,进入对应国际化功能输出判断显示界面。 +4. 功能界面中点击返回按钮,返回主页面。 +5. 测试超时设置为:Time out(s):30。 + +### 工程目录 + +``` +Internationalization +entry/src/main + │ module.json5 // 模块配置文件 + │ + ├─ets + │ ├─component + │ │ TitleBar.ets // 公共标题栏 + │ │ AssertEqual.ets // 断言判断函数 + │ │ + │ ├─entryability + │ │ EntryAbility.ets // 程序入口类 + │ │ + │ ├─entrybackupability + │ │ EntryBackupAbility.ets + │ │ + │ ├─i18napplication // 页面文件 + │ │ CalendarSetting.ets // 设置日历和历法界面 + │ │ CharacterProcessing.ets // 字符处理界面 + │ │ DateTimeFormatting.ets // 时间日期国际化界面 + │ │ LanguagePreferenceSetting.ets // 设置语言与用户偏好界面 + │ │ LocaleCulturalDivision.ets // 区域标识与文化习惯划分界面 + │ │ MultilingualSorting.ets // 多语言排序界面 + │ │ NameLocalization.ets // 本地化名称界面 + │ │ NumberMeasurementFormatting.ets // 数字与度量衡国际化界面 + │ │ PhoneNumberFormatting.ets // 电话号码格式化界面 + │ │ TimezoneDstSetting.ets // 时区与夏时令国际化界面 + │ │ + │ └─pages + │ Index.ets // 主界面 + │ + └─resources // 资源文件目录 +``` + +### 具体实现 + +- 设置在主页面集成所有功能界面模块,将`Listitem`中`Row`组件设置点击事件进入相关需求界面模块的展示。 + +- 每个子模块页面的实现代码对应国际化开发指南中的具体章节,子模块目录按其功能进行命名,如`DateTimeFormatting(时间日期格式化)`,示例代码内容由`Text`文本输出显示。 + +- 公共功能(如标题栏)提取为公共组件供各个子模块复用,设置公共组件`TitleBar`标题栏展示需求界面模块的功能名称,公共功能(如标题栏)提取为公共组件供各个子模块复用。 + +### 相关权限 + +[ohos.permission.UPDATE_CONFIGURATION](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.0-Beta1/zh-cn/application-dev/security/AccessToken/permissions-for-system-apps.md#ohospermissionupdate_configuration) + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:RK3568。 +2. 本示例为Stage模型,支持API14版本SDK,版本号:5.1.0.44。 +3. 支持的IDE版本:本示例已支持DevEco Studio 5.0.1 Release (构建版本:5.0.5.306,构建 2024年12月6日)编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/International/Internationalization > .git/info/sparse-checkout +git remote add origin https://gitee.com/openharmony/applications_app_samples.git +git pull origin master +``` \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/build-profile.json5 b/code/DocsSample/International/Internationalization/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9b050d3379574473f892f128254ce383d5513793 --- /dev/null +++ b/code/DocsSample/International/Internationalization/build-profile.json5 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": 14, + "compileSdkVersion": 14, + "targetSdkVersion": 14, + "runtimeOS": "OpenHarmony" + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/.gitignore b/code/DocsSample/International/Internationalization/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/build-profile.json5 b/code/DocsSample/International/Internationalization/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b7b723d6bc9df0cec043eac828cc8bc1bb0beaf9 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/build-profile.json5 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + "runtimeOS": "OpenHarmony" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/hvigorfile.ts b/code/DocsSample/International/Internationalization/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4f43d54667f8327c367c8096bd08bb8c75aff54 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/code/DocsSample/International/Internationalization/entry/obfuscation-rules.txt b/code/DocsSample/International/Internationalization/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..69c4d6a8a5531548e4886fa766090c5c157a87d9 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/obfuscation-rules.txt @@ -0,0 +1,18 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/oh-package.json5 b/code/DocsSample/International/Internationalization/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9cb6c8174858277c9b0d465a51547dcab16d5ff --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/component/AssertEqual.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/component/AssertEqual.ets new file mode 100644 index 0000000000000000000000000000000000000000..74ad4c496a7a3a8cdd2ae589637309fecfec98b5 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/component/AssertEqual.ets @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function assertEqual(actual: T, expected: T, description: Resource): string { + if (actual === expected) { + return `${getContext().resourceManager.getStringSync(description)}${expected} --passed`; + } else { + return `${getContext().resourceManager + .getStringSync(description)} --failed: expected ${expected}, but got ${actual}`; + } +} + +export function assertEqualLong(actual: string, expected: string[], description: Resource): string { + if (expected.every(expected => actual.includes(expected))) { + return `${getContext().resourceManager.getStringSync(description)}passed`; + } else { + return `${getContext().resourceManager.getStringSync(description)}failed: expected ${expected}, but got ${actual}`; + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/component/TitleBar.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/component/TitleBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..f3cbe555d1961c2149ac4679d5b34bf2a49cf3f1 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/component/TitleBar.ets @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import router from '@ohos.router'; + +@Component +export default struct TitleBar { + private title: string | Resource = $r('app.string.Internationalization'); + private hasBackPress: boolean = false; + + build() { + Row() { + if (this.hasBackPress) { + Row() { + Image($r('app.media.back')) + .id('btnBack') + .width(12) + .height(12) + } + .height('100%') + .aspectRatio(1) + .margin({ left: 24 }) + .onClick(() => { + router.back() + }) + } + Text(this.title) + .fontSize(20) + .fontColor(Color.Black) + .margin(this.hasBackPress ? {} : { left: 24 }) + Blank() + } + .width('100%') + .height(56) + .backgroundColor(Color.Transparent) + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/entryability/EntryAbility.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..0f2f8b94aa24b0a50e272270e4e18b6df93ac5fd --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/CalendarSetting.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/CalendarSetting.ets new file mode 100644 index 0000000000000000000000000000000000000000..5d6f3da17f340c428a0f38b100fbc644adfb89d9 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/CalendarSetting.ets @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual } from '../component/AssertEqual'; +import { i18n } from '@kit.LocalizationKit'; + +// 设置日历和历法开发实例 +// 公历相关用法 +let calendar: i18n.Calendar = i18n.getCalendar('zh-Hans', 'gregory'); + +// 设置日历对象的日期 +calendar.setTime(new Date(2022, 5, 13, 8, 0, 0)); +calendar.setTime(10540800000); + +// 设置日历对象的年、月、日、时、分、秒 +calendar.set(2022, 5, 13, 8, 0, 0); + +// 设置日历对象的时区 +calendar.setTimeZone('Asia/Shanghai'); + +// 获取日历对象的时区 +let timezone: string = calendar.getTimeZone(); // Asia/Shanghai + +// 获取日历对象的一周起始日 +let firstDayOfWeek: number = calendar.getFirstDayOfWeek(); // 1 + +// 设置每一周的起始日 +calendar.setFirstDayOfWeek(1); + +// 获取一年中第一周的最小天数 +let minimalDaysInFirstWeek: number = calendar.getMinimalDaysInFirstWeek(); // 1 + +// 设置一年中第一周的最小天数 +calendar.setMinimalDaysInFirstWeek(3); + +// 获取日历对象中与field相关联的值 +let value: number = calendar.get('year'); // 2022 + +// 获取日历对象本地化名称 +let calendarName: string = calendar.getDisplayName('zh-Hans'); // 公历 + +// 判断指定的日期在日历中是否为周末 +let isWeekend: boolean = calendar.isWeekend(new Date(2023, 9, 15)); // true + +// 在日历的给定字段进行加减操作 +calendar.set(2023, 10, 15); +calendar.add('date', 2); +calendar.get('date'); // 17 + +// 比较日历和指定日期相差的天数 +calendar.compareDays(new Date(2023, 10, 15)); // -3 + +// 获取公历对应的农历日期 +let calendar_ch: i18n.Calendar = i18n.getCalendar('zh-Hans', 'chinese'); + +// 将公历信息设置到calendar对象 +calendar_ch.setTime(new Date(2023, 6, 25, 8, 0, 0)); + +// 获取农历年月日 +calendar_ch.get('year'); // 返回干支纪年40,范围1-60 +calendar_ch.get('month'); // 结果为5,指6月 +calendar_ch.get('date'); // 8日 + +const expectedTimezone = 'Asia/Shanghai'; +const expectedFirstDayOfWeek = 1; +const expectedMinimalDaysInFirstWeek = 1; +const expectedValue = 2022; +const expectedCalendarName = '公历'; +const expectedIsWeekend = true; +const expectedDateAddTwoDays = 17; +const expectedCompareDays = -3; +const expectedCalendarYear = 40; +const expectedCalendarMonth = 5; +const expectedCalendarDate = 8; + +@Extend(Text) +function textStyle() { + .fontSize(20).margin({ top: 15, left: 20, right: 20 }); +} + +@Entry +@Component +struct CalendarSetting { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.CalendarSetting') }) + Text($r('app.string.ResultsOfTheGregorianCalendar')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text($r('app.string.TheGregorianCalendarSets')) + .textStyle() + Text(assertEqual(timezone, expectedTimezone, $r('app.string.Timezone'))) + .textStyle() + Text(assertEqual(firstDayOfWeek, expectedFirstDayOfWeek, $r('app.string.FirstDayOfWeek'))) + .textStyle() + Text(assertEqual(minimalDaysInFirstWeek, expectedMinimalDaysInFirstWeek, $r('app.string.MinimalDaysInFirstWeek'))) + .textStyle() + Text($r('app.string.SetMinimalDaysInFirstWeek')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(value, expectedValue, $r('app.string.YearOfTheFirstWeekIs3'))) + .textStyle() + Text(assertEqual(calendarName, expectedCalendarName, $r('app.string.LocalizedCalendarName'))) + .textStyle() + Text(assertEqual(isWeekend, expectedIsWeekend, $r('app.string.IsWeekend'))) + .textStyle() + Text(assertEqual(calendar.get('date'), expectedDateAddTwoDays, $r('app.string.DateAfterAddingDays'))) + .textStyle() + Text(assertEqual(calendar.compareDays(new Date(2023, 10, 15)), expectedCompareDays, + $r('app.string.DaysBetweenDates'))) + .textStyle() + Text($r('app.string.LunarCalendar')) + .textStyle().fontWeight(FontWeight.Bold) + Text(assertEqual(calendar_ch.get('year'), expectedCalendarYear, $r('app.string.LunarYear'))) + .textStyle() + Text(assertEqual(calendar_ch.get('month'), expectedCalendarMonth, $r('app.string.LunarMonth'))) + .textStyle() + Text(assertEqual(calendar_ch.get('date'), expectedCalendarDate, $r('app.string.LunarDate'))) + .textStyle() + }.width('100%').height('100%').alignItems(HorizontalAlign.Start) + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/CharacterProcessing.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/CharacterProcessing.ets new file mode 100644 index 0000000000000000000000000000000000000000..c5d2a067a08118bb6b4ed564dbc5710f8befd047 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/CharacterProcessing.ets @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual, assertEqualLong } from '../component/AssertEqual'; +import { i18n } from '@kit.LocalizationKit'; + +/********************************************************************************************************************** + * 字符属性开发参考步骤 + * 1. 导入模块 + * import { i18n } from '@kit.LocalizationKit'; + * 2. 判断字符属性 + * let isDigit: boolean = i18n.Unicode.isDigit(char: string); + * 3. 以一般类别值为例,判断字符类类型,具体请参考getType接口文档 + * let type = i18n.Unicode.getType(char: string); + *********************************************************************************************************************/ + +// 判断字符是否是数字 +let isDigit = i18n.Unicode.isDigit('1'); // isDigit: true + +// 判断字符是否是从右到左语言的字符 +let isRTL = i18n.Unicode.isRTL('a'); // isRTL: false + +// 判断字符是否是表意文字 +let isIdeograph = i18n.Unicode.isIdeograph('华'); // isIdeograph: true + +// 获取字符的一般类别值 +let type = i18n.Unicode.getType('a'); // type: U_LOWERCASE_LETTER + +/********************************************************************************************************************** + * 音译开发参考步骤 + * 1. 导入模块 + * import { i18n } from '@kit.LocalizationKit'; + * 2. 创建Transliterator对象,获取音译列表 + * // 传入音译支持的ID,创建Transliterator对象 + * let transliterator: i18n.Transliterator = i18n.Transliterator.getInstance(id: string); + * let ids: string[] = i18n.Transliterator.getAvailableIDs(); // 获取音译支持的ID列表 + * 3. 音译文本 + * let res: string = transliterator.transform(text: string); // 对text内容进行音译 + *********************************************************************************************************************/ + +// 音译成Latn格式 +let transliterator = i18n.Transliterator.getInstance('Any-Latn'); +let wordArray = ['中国', '德国', '美国', '法国'] +let transRes: Array = []; +for (let i = 0; i < wordArray.length; i++) { + let res = transliterator.transform(wordArray[i]); // res: zhōng guó, dé guó, měi guó, fǎ guó + transRes.push(res); +} + +// 汉语音译去声调 +let transliter = i18n.Transliterator.getInstance('Any-Latn;Latin-Ascii'); +let result = transliter.transform('中国'); // result: zhong guo + +// 汉语姓氏读音 +let nameTransliter = i18n.Transliterator.getInstance('Han-Latin/Names'); +let result1 = nameTransliter.transform('单老师'); // result1: shàn lǎo shī +let result2 = nameTransliter.transform('长孙无忌'); // result2: zhǎng sūn wú jì + +// 获取音译支持的ID列表 +let ids = i18n.Transliterator.getAvailableIDs(); // ids: ['ASCII-Latin', 'Accents-Any', ...] + +/********************************************************************************************************************** + * 字符标准化开发参考步骤 + * 1. 导入模块 + * import { i18n } from '@kit.LocalizationKit'; + * 2. 创建标准化对象 + * let normalizer: i18n.Normalizer = i18n.Normalizer.getInstance(mode: NormalizerMode); + * 3. 文本标准化 + * let normalizedText: string = normalizer.normalize(text: string); // 对text文本进行标准化 + *********************************************************************************************************************/ + +// 以NFC范式标准化字符 +let normalizer = i18n.Normalizer.getInstance(i18n.NormalizerMode.NFC); +let normalizedText = normalizer.normalize('\u1E9B\u0323'); // normalizedText: \u1E9B\u0323 + +/********************************************************************************************************************** + * 断词换行开发参考步骤 + * 1. 导入模块 + * import { i18n } from '@kit.LocalizationKit'; + * 2. 创建用于断句的对象 + * let iterator: i18n.BreakIterator = i18n.getLineInstance(locale: string); + * 3. 设置要处理的文本 + * iterator.setLineBreakText(text: string); // 设置要处理的文本 + * let breakText: string = iterator.getLineBreakText(); // 查看iterator正在处理的文本 + * 4. 获取可断句的位置 + * // 获取iterator在当前所处理文本中的位置 + * let currentPos: number = iterator.current(); + * // 设置为第一个可断句的分割点,返回该分割点的位置。第一个分割点总是在文本的起始位置,firstPos = 0 + * let firstPos: number = iterator.first(); + * // 将iterator移动number数量个分割点,number为正数代表向后移动,number为负数代表向前移动,默认值为1。 + * // nextPos为移动后在文本中的位置,如果超出文本的长度范围,返回-1 + * let nextPos: number = iterator.next(number); + * // 判断number位置是否是分割点 + * let isBoundary: boolean = iterator.isBoundary(number); + *********************************************************************************************************************/ + +// 断句对象 +let iterator = i18n.getLineInstance('en-GB'); + +// 断句文本 +iterator.setLineBreakText('Apple is my favorite fruit.'); + +// 将BreakIterator对象移动到文本起始位置 +let firstPos = iterator.first(); // firstPos: 0 + +// 将BreakIterator对象移动几个分割点 +let nextPos = iterator.next(2); // nextPos: 9 + +// 判断某个位置是否是分割点 +let isBoundary = iterator.isBoundary(9); // isBoundary: true + +// 获取BreakIterator对象处理的文本 +let breakText = iterator.getLineBreakText(); // breakText: Apple is my favorite fruit. + +const expectedIsDigit = true; +const expectedIsRTL = false; +const expectedIsIdeograph = true; +const expectedType = 'U_LOWERCASE_LETTER'; +const expectedTransResult = 'zhōng guó,dé guó,měi guó,fǎ guó'; +const expectedResult = 'zhong guo'; +const expectedResult1 = 'shàn lǎo shī'; +const expectedResult2 = 'zhǎng sūn wú jì'; +const expectedIds = ['ASCII-Latin', 'Accents-Any']; +const expectedNormalizedText = 'ẛ̣'; +const expectedFirstPos = 0; +const expectedNextPos = 9; +const expectedIsBoundary = true; +const expectedBreakText = 'Apple is my favorite fruit.'; + +@Extend(Text) +function textStyle() { + .fontSize(18) + .margin({ top: 15, left: 20, right: 20 }); +} + +@Entry +@Component +export default struct CharacterProcessing { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.CharacterProcessing') }) + Scroll() { + Column() { + Text($r('app.string.ResultsOfCharacterType')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(isDigit, expectedIsDigit, $r('app.string.Character1IsNumber'))) + .textStyle() + Text(assertEqual(isRTL, expectedIsRTL, $r('app.string.AIsRightToLeft'))) + .textStyle() + Text(assertEqual(isIdeograph, expectedIsIdeograph, $r('app.string.HuaIsIdeograph'))) + .textStyle() + Text(assertEqual(type, expectedType, $r('app.string.AGetType'))) + .textStyle() + Text($r('app.string.ResultsOfTrans')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(transRes.join(','), expectedTransResult, $r('app.string.CharacterTransResult'))) + .textStyle() + Text(assertEqual(result, expectedResult, $r('app.string.ChinaTrans'))) + .textStyle() + Text(assertEqual(result1, expectedResult1, $r('app.string.TeachersSurnameTrans'))) + .textStyle() + Text(assertEqual(result2, expectedResult2, $r('app.string.ZhangSunWuJiTrans'))) + .textStyle() + Text(assertEqualLong(ids.join(', '), expectedIds, $r('app.string.ResultsOfSupportedId'))) + .textStyle() + Scroll() { + Text(ids.join(', ')) + .textStyle() + .id('transIdsText') + } + .id('transIdsScroll') + .margin({ left: 50 }) + .border({ + width: 2, + color: $r('app.color.Border_Gray'), + style: BorderStyle.Solid, + radius: 10 + }) + .width('80%') + .height('20%') + + Text($r('app.string.ResultsOfNormalize')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(normalizedText, expectedNormalizedText, $r('app.string.NFCNormalizeResult'))) + .textStyle() + Text($r('app.string.ResultsOfBreakIterator')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(firstPos, expectedFirstPos, $r('app.string.FirstPos'))) + .textStyle() + Text(assertEqual(nextPos, expectedNextPos, $r('app.string.NextPos'))) + .textStyle() + Text(assertEqual(isBoundary, expectedIsBoundary, $r('app.string.IsBoundary'))) + .textStyle() + Text(assertEqual(breakText, expectedBreakText, $r('app.string.BreakText'))) + .textStyle() + Blank().height('10%') + } + .alignItems(HorizontalAlign.Start) + } + .id('outerScrollInCharacter') + .width('100%') + .height('100%') + } + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/DateTimeFormatting.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/DateTimeFormatting.ets new file mode 100644 index 0000000000000000000000000000000000000000..aee2558aca713dbf572a0bab4e271850c0796a29 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/DateTimeFormatting.ets @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual } from '../component/AssertEqual'; +import { intl } from '@kit.LocalizationKit'; + +/********************************************************************************************************************** + * 时间日期格式化开发参考步骤 + * 1. 导入模块 + * import { intl } from '@kit.LocalizationKit'; + * 2. 创建DateTimeFormat对象 + * let dateFormat: intl.DateTimeFormat = + * new intl.DateTimeFormat(locale: string | Array, options?: DateTimeOptions); + * let dateFormat: intl.DateTimeFormat = new intl.DateTimeFormat(); //不传入locale参数 + * 3. 时间日期和相对时间格式化 + * - 时间日期格式化 + * let formattedDate: string = dateFormat.format(date: Date); + * - 相对时间格式化 + * let formattedDate: string = dateFormat.format(date: Date); + * 4. 获取格式化选项,查看对象的设置信息 + * let options: intl.DateTimeOptions = dateFormat.resolvedOptions(); + *********************************************************************************************************************/ + +// 时间日期格式化开发实例 +// 设置要格式化的日期 +let date = new Date(2021, 8, 17, 13, 4, 0); +let startDate = new Date(2021, 8, 17, 13, 4, 0); +let endDate = new Date(2021, 8, 18, 13, 4, 0); + +// 在软件上展示完整的时间信息 +let dateFormat1 = new intl.DateTimeFormat('zh-CN', { dateStyle: 'full', timeStyle: 'full' }); +let formattedDate1 = dateFormat1.format(date); // formattedDate1: 2021年9月17日星期五 中国标准时间 13:04:00 + +// 在有限的空间展示简短的时间信息 +let dateFormat2 = new intl.DateTimeFormat('zh-CN', { dateStyle: 'short', timeStyle: 'short' }); +let formattedDate2 = dateFormat2.format(date); // formattedDate2: 2021/9/17 13:04 + +// 自定义年月日时分秒的显示效果 +let dateFormat3 = new intl.DateTimeFormat('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' +}); +let formattedDate3 = dateFormat3.format(date); // formattedDate3: 2021/09/17 13:04:00 + +// 仅显示一部分时间 +let dateFormat4 = new intl.DateTimeFormat('zh-CN', { month: 'long', day: 'numeric', weekday: 'long' }); +let formattedDate4 = dateFormat4.format(date); // formattedDate4: 9月17日星期五 + +// 自定义时制格式 +let dateFormat5 = new intl.DateTimeFormat('zh-CN', { dateStyle: 'short', timeStyle: 'short', hourCycle: 'h11' }); +let formattedDate5 = dateFormat5.format(date); // formattedDate5: 2021/9/17 下午13:04 + +// 面向习惯于其他数字系统的用户 +let dateFormat6 = new intl.DateTimeFormat('zh-CN', { dateStyle: 'short', timeStyle: 'short', numberingSystem: 'arab' }); +let formattedDate6 = dateFormat6.format(date); // formattedDate6: ٢٠٢١/٩/١٧ ١٣:٠٤ + +// 格式化时间段 +let dataFormat7 = new intl.DateTimeFormat('en-GB'); +let formattedDateRange = dataFormat7.formatRange(startDate, endDate); // formattedDateRange: 17/09/2021 - 18/09/2021 + +// 获取格式化选项 +let dataFormat8 = new intl.DateTimeFormat('en-GB', { dateStyle: 'full' }); +let options = dataFormat8.resolvedOptions(); +let dateStyle = options.dateStyle; // dateStyle: full + +/********************************************************************************************************************** + * 相对时间格式化开发参考步骤 + * 1. 导入模块 + * import { intl } from '@kit.LocalizationKit'; + * 2. 创建RelativeTimeFormat对象 + * let relativeTimeFormat: intl.RelativeTimeFormat = + * new intl.RelativeTimeFormat(locale: string | Array, options?: RelativeTimeFormatInputOptions); + * 3. 格式化相对时间 + * let formattedRelativeTime: string = relativeTimeFormat.format(value: number, unit: string); + * 4. 自定义相对时间的格式化 + * let parts: Array = relativeTimeFormat.formatToParts(value: number, unit: string); + * 5. 获取相对时间格式化选项,查看对象的设置信息 + * let options: intl.RelativeTimeFormatInputOptions = relativeTimeFormat.resolvedOptions(); + *********************************************************************************************************************/ + +// 相对时间格式化开发实例 +// 显示相对时间 +let relativeTimeFormat1 = new intl.RelativeTimeFormat('en-GB'); +let formattedRelativeTime1 = relativeTimeFormat1.format(-1, 'day'); // formattedRelativeTime1: 1 day ago + +// 口语化 +let relativeTimeFormat2 = new intl.RelativeTimeFormat('en-GB', { numeric: 'auto' }); +let formattedRelativeTime2 = relativeTimeFormat2.format(-1, 'day'); // formattedRelativeTime2: yesterday + +// 部分语言支持更为简短的显示风格 +let relativeTimeFormat3 = new intl.RelativeTimeFormat('fr-FR'); // 默认style为long +let formattedRelativeTime3 = relativeTimeFormat3.format(-1, 'day'); // formattedRelativeTime3: il y a 1 jour +let relativeTimeFormat4 = new intl.RelativeTimeFormat('fr-FR', { style: 'narrow' }); +let formattedRelativeTime4 = relativeTimeFormat4.format(-1, 'day'); // formattedRelativeTime4: -1 j + +// 自定义区域设置格式的相对时间格式 +let relativeTimeFormat5 = new intl.RelativeTimeFormat('en-GB', { style: 'long' }); +// parts: [{type: 'literal', value: 'in'}, {type: 'integer', value: 1, unit: 'day'}, {type: 'literal', value: 'day'}] +let parts = relativeTimeFormat5.formatToParts(1, 'day'); + +// 获取RelativeTimeFormat对象的格式化选项 +let relativeTimeFormat6 = new intl.RelativeTimeFormat('en-GB', { numeric: 'auto' }); +let relativeOptions = relativeTimeFormat6.resolvedOptions(); +let numeric = relativeOptions.numeric; // numeric: auto + +const expectedFormattedDate1 = '2021年9月17日星期五 中国标准时间 13:04:00'; +const expectedFormattedDate2 = '2021/9/17 13:04'; +const expectedFormattedDate3 = '2021/09/17 13:04:00'; +const expectedFormattedDate4 = '9月17日星期五'; +const expectedFormattedDate5 = '2021/9/17 下午13:04'; +const expectedFormattedDate6 = '٢٠٢١/٩/١٧ ١٣:٠٤'; +const expectedFormattedDateRange = '17/09/2021 – 18/09/2021'; +const expectedDateStyle = 'full'; +const expectedFormattedRelativeTime1 = '1 day ago'; +const expectedFormattedRelativeTime2 = 'yesterday'; +const expectedFormattedRelativeTime3 = 'il y a 1 jour'; +const expectedFormattedRelativeTime4 = '-1 j'; +const expectedCustomFormat = + '[{\"type\":\"literal\",\"value\":\"in \"},' + + '{\"type\":\"integer\",\"value\":\"1\",\"unit\":\"day\"},' + + '{\"type\":\"literal\",\"value\":\" day\"}]'; +const expectedNumeric = 'auto'; + +@Extend(Text) +function textStyle() { + .fontSize(20) + .margin({ top: 12, left: 30, right: 30 }); +} + +@Entry +@Component +struct DateTimeFormatting { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.DateTimeFormatting') }) + Scroll() { + Column() { + Text($r('app.string.ResultsOfDateTimeFormat')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(formattedDate1, expectedFormattedDate1, $r('app.string.FullDateStyle'))) + .textStyle() + Text(assertEqual(formattedDate2, expectedFormattedDate2, $r('app.string.ShortDateStyle'))) + .textStyle() + Text(assertEqual(formattedDate3, expectedFormattedDate3, $r('app.string.CustomDateStyle'))) + .textStyle() + Text(assertEqual(formattedDate4, expectedFormattedDate4, $r('app.string.PartDateStyle'))) + .textStyle() + Text(assertEqual(formattedDate5, expectedFormattedDate5, $r('app.string.CustomTimeStyle'))) + .textStyle() + Text(assertEqual(formattedDate6, expectedFormattedDate6, $r('app.string.CustomNumberingSystem'))) + .textStyle() + Text(assertEqual(formattedDateRange, expectedFormattedDateRange, $r('app.string.FormatDateRange'))) + .textStyle() + Text(assertEqual(dateStyle, expectedDateStyle, $r('app.string.FormatDateStyle'))) + .textStyle() + Text($r('app.string.ResultsOfRelativeTimeFormat')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(formattedRelativeTime1, expectedFormattedRelativeTime1, $r('app.string.FormatRelativeTime'))) + .textStyle() + Text(assertEqual(formattedRelativeTime2, expectedFormattedRelativeTime2, + $r('app.string.AutoFormatRelativeTime'))) + .textStyle() + Text(assertEqual(formattedRelativeTime3, expectedFormattedRelativeTime3, + $r('app.string.LongFormatRelativeTime'))) + .textStyle() + Text(assertEqual(formattedRelativeTime4, expectedFormattedRelativeTime4, + $r('app.string.NarrowFormatRelativeTime'))) + .textStyle() + Text(assertEqual(JSON.stringify(parts), expectedCustomFormat, $r('app.string.CustomFormatRelativeTime'))) + .textStyle() + Text(assertEqual(numeric, expectedNumeric, $r('app.string.GetRelativeTimeFormatOptions'))) + .textStyle() + Blank().height('10%') + } + .alignItems(HorizontalAlign.Start) + } + .id('outerScrollInDateTime') + .width('100%') + .height('100%') + } + } +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/LanguagePreferenceSetting.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/LanguagePreferenceSetting.ets new file mode 100644 index 0000000000000000000000000000000000000000..b3cb9c0e05325a55abc93e02dbfc516d3cd2c6dc --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/LanguagePreferenceSetting.ets @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual } from '../component/AssertEqual'; +import { i18n, intl } from '@kit.LocalizationKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +/********************************** + * 设置系统语言与区域 + *********************************/ +// 设置系统当前语言为 'zh' +let systemLanguage = '' +try { + i18n.System.setSystemLanguage('zh'); + systemLanguage = i18n.System.getSystemLanguage(); // systemLanguage为当前系统语言 +} catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`call System.setSystemLanguage failed, error code: ${err.code}, message: ${err.message}.`); +} + +// 设置系统当前地区为 'CN' +let systemRegion = ''; +try { + i18n.System.setSystemRegion('CN'); + systemRegion = i18n.System.getSystemRegion(); // systemRegion为当前系统地区 +} catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`call System.setSystemRegion failed, error code: ${err.code}, message: ${err.message}.`); +} + +// 设置系统当前区域为 'zh-Hans-CN' +let systemLocale = ''; +try { + i18n.System.setSystemLocale('zh-Hans-CN'); + systemLocale = i18n.System.getSystemLocale(); // systemLocale为当前系统区域 +} catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`call System.setSystemLocale failed, error code: ${err.code}, message: ${err.message}.`); +} + +/********************************** + * 设置应用偏好语言 + *********************************/ +// 设置应用的偏好语言 +let appPreferredLanguage = ''; +try { + i18n.System.setAppPreferredLanguage('zh-Hans'); // 设置应用偏好语言为zh-Hans + appPreferredLanguage = i18n.System.getAppPreferredLanguage(); // 获取应用偏好语言 +} catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`call System.setAppPreferredLanguage failed, error code: ${err.code}, message: ${err.message}.`); +} + +// 清除应用的偏好语言 +try { + i18n.System.setAppPreferredLanguage('default'); // 清除应用的偏好语言 +} catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`call System.setAppPreferredLanguage failed, error code: ${err.code}, message: ${err.message}.`); +} + +/********************************** + * 设置用户偏好 + *********************************/ +// 设置应用界面数字 +try { + i18n.System.setUsingLocalDigit(true); // 打开本地化数字开关 +} catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`call System.setUsingLocalDigit failed, error code: ${err.code}, message: ${err.message}.`); +} +let date1 = new Date(2023, 9, 25); +let appPreferredLanguage1 = 'ar'; +let dateTimeFmt1 = new intl.DateTimeFormat(appPreferredLanguage1); +let result1 = dateTimeFmt1.format(date1); // result = "٢٠٢٣/١٠/٢٥"(采用阿语本地数字表示) + +// 设置格式化的24小时制 +try { + i18n.System.set24HourClock(true); // true表示打开24小时制开关,false表示打开12小时制开关 +} catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`call System.set24HourClock failed, error code: ${err.code}, message: ${err.message}.`); +} +let date2 = new Date(2023, 9, 25, 16, 48, 0); +let appPreferredLanguage2 = 'zh'; +let dateTimeFmt2 = new intl.DateTimeFormat(appPreferredLanguage2, { timeStyle: 'medium' }); +let result2 = dateTimeFmt2.format(date2); // result = "16:48:00" + +const expectedSystemLanguage = 'zh'; +const expectedSystemRegion = 'CN'; +const expectedSystemLocale = 'zh-Hans-CN'; +const expectedAppPreferredLanguage = 'zh-Hans'; +const expectedResult1 = '٢٥‏/١٠‏/٢٠٢٣'; +const expectedResult2 = '16:48:00'; + +@Extend(Text) +function textStyle() { + .fontSize(20) + .margin({ top: 20, left: 30, right: 20 }); +} + +@Entry +@Component +struct LanguagePreferenceSetting { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.LanguagePreferenceSetting') }) + Text($r('app.string.ResultsOfSetSystemLanguageAndRegion')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(systemLanguage, expectedSystemLanguage, $r('app.string.SetAndGetSystemLanguage'))) + .textStyle() + Text(assertEqual(systemRegion, expectedSystemRegion, $r('app.string.SetAndGetSystemRegion'))) + .textStyle() + Text(assertEqual(systemLocale, expectedSystemLocale, $r('app.string.SetAndGetSystemLocale'))) + .textStyle() + Text($r('app.string.ResultsOfSetPreferredLanguage')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(appPreferredLanguage, expectedAppPreferredLanguage, $r('app.string.SetAndGetPreferredLanguage'))) + .textStyle() + Text($r('app.string.ResultsOfSetUserPreference')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(result1, expectedResult1, $r('app.string.SetApplicationInterfaceNumber'))) + .textStyle() + Text(assertEqual(result2, expectedResult2, $r('app.string.SetFormatTo24Format'))) + .textStyle() + } + .width('100%') + .height('100%') + .alignItems(HorizontalAlign.Start) + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/LocaleCulturalDivision.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/LocaleCulturalDivision.ets new file mode 100644 index 0000000000000000000000000000000000000000..b18804a594c76bf0dd2aa1c3e8945fcc79e7249d --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/LocaleCulturalDivision.ets @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual } from '../component/AssertEqual'; +import { intl } from '@kit.LocalizationKit'; + +// 创建区域标识对象。格式化时间日期如下给出了三种方法: +let date = new Date(2023, 9, 15); + +// 方法一: 通过区域标识字符串创建区域标识对象 +let zhLocale = new intl.Locale('zh-Hans-CN-u-nu-latn'); +let zhDateTimeFmt = new intl.DateTimeFormat(zhLocale.toString()); +let result1 = zhDateTimeFmt.format(date); // result = "2023/10/15" + +// 方法二: 通过区域标识字符串和LocaleOptions对象创建区域标识对象 +let enLocale = new intl.Locale('en', { numberingSystem: 'latn' }); +let enDateTimeFmt = new intl.DateTimeFormat(enLocale.toString()); +let result2 = enDateTimeFmt.format(date); // result = "10/15/23" + +// 方法三: 通过默认Locale函数创建系统区域标识对象 +let systemLocale = new intl.Locale(); +let systemDateTimeFmt = new intl.DateTimeFormat(systemLocale.toString()); +let result3 = systemDateTimeFmt.format(date); // result = "2023/10/15" (具体显示效果依赖于当前系统环境) + +const expectedResult1 = '2023/10/15'; +const expectedResult2 = '10/15/23'; +const expectedResult3 = '2023/10/15'; + +@Extend(Text) +function textStyle() { + .fontSize(20) + .margin({ top: 20, left: 30, right: 30 }); +} + +@Entry +@Component +struct LocaleCulturalDivision { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.LocaleCulturalDivision') }) + Text($r('app.string.MethodOne')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(result1, expectedResult1, $r('app.string.ResultOfMethodOne'))) + .textStyle() + Text($r('app.string.MethodTwo')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(result2, expectedResult2, $r('app.string.ResultOfMethodTwo'))) + .textStyle() + Text($r('app.string.MethodThree')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(result3, expectedResult3, $r('app.string.ResultOfMethodThree'))) + .textStyle() + } + .width('100%') + .height('100%') + .alignItems(HorizontalAlign.Start) + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/MultilingualSorting.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/MultilingualSorting.ets new file mode 100644 index 0000000000000000000000000000000000000000..edaadec826cbf5deb03aa57a787f3404a3ed6bd7 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/MultilingualSorting.ets @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual, assertEqualLong } from '../component/AssertEqual'; +import { i18n, intl } from '@kit.LocalizationKit'; + +/***************************************************************************************************************************** + * 本地习惯排序开发参考步骤 + * 1. 导入模块 + * import { intl } from '@kit.LocalizationKit'; + * 2. 创建collator排序对象 + * let collator = new intl.Collator(locale: string | Array, options?: CollatorOptions); + * 3. 比较字符串 + * let compareResult = collator.compare(first: string, second: string); + * // compareResult 为负数,表示第一个参数排在第二个参数之前 + * // compareResult 为0,表示第一个参数与第二个参数排序不分先后 + * // compareResult 为正数,表示第一个参数排在第二个参数之后 + *****************************************************************************************************************************/ + +// 创建排序对象 +let options: intl.CollatorOptions = { + localeMatcher: 'lookup', + usage: 'sort', + sensitivity: 'case' // 区分大小写 +}; +let collator = new intl.Collator('zh-CN', options); + +// 区分大小写排序 +let enArray = ['app', 'App', 'Apple', 'ANIMAL', 'animal', 'apple', 'APPLE']; +enArray.sort((a, b) => { + return collator.compare(a, b); +}) +console.log('result: ', enArray); // animal ANIMAL app App apple Apple APPLE + +// 中文拼音排序 +let zhArray = ['苹果', '梨', '香蕉', '石榴', '甘蔗', '葡萄', '橘子']; +zhArray.sort((a, b) => { + return collator.compare(a, b); +}) +console.log('result: ', zhArray); // 甘蔗,橘子,梨,苹果,葡萄,石榴,香蕉 + +// 按笔画排序 +options = { + localeMatcher: 'lookup', + usage: 'sort', + collation: 'stroke' +}; +collator = new intl.Collator('zh-CN', options); +let zhStrokeArray = ['苹果', '梨', '香蕉', '石榴', '甘蔗', '葡萄', '橘子']; +zhStrokeArray.sort((a, b) => { + return collator.compare(a, b); +}) +console.log('result: ', zhStrokeArray); // 甘蔗,石榴,苹果,香蕉,梨,葡萄,橘子 + +// 搜索匹配的字符串 +options = { + usage: 'search', + sensitivity: 'base' +}; +collator = new intl.Collator('tr', options); +let sourceArray = ['Türkiye', 'TüRkiye', 'salt', 'bright']; +let s = 'türkiye'; +let matches = sourceArray.filter(item => collator.compare(item, s) === 0); +console.log(matches.toString()); // Türkiye,TüRkiye + +/********************************************************************************************************************** + * 创建索引开发参考步骤 + * 1. 导入模块 + * import { i18n } from '@kit.LocalizationKit'; + * 2. 创建对象 + * let indexUtil = i18n.getInstance(locale?:string); // locale 表示本地化标识符,默认值是系统当前locale + * 3. 以获取索引列表为例 + * let indexList = indexUtil.getIndexList(); + *********************************************************************************************************************/ + +// 创建索引开发实例 +// 创建索引 +let indexUtil = i18n.getInstance('zh-CN'); +let indexList = indexUtil.getIndexList(); // ['...', 'A', 'B', 'C', 'D', 'E' ... 'X', 'Y', 'Z', '...'] +// 多语言index混排 +indexUtil.addLocale('ru-RU'); +// …,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,…,А,Б,В,Г,Д,Е,Ж,З,И,Й,К,Л,М,Н,О,П,Р,С,Т,У,Ф,Х,Ц,Ч,Ш,Щ,Ы,Э,Ю,Я,… +indexList = indexUtil.getIndexList(); +indexUtil.getIndex('你好'); // N + +const expectedEnglishSort = 'animal ANIMAL app App apple Apple APPLE'; +const expectedChineseSort = '甘蔗,橘子,梨,苹果,葡萄,石榴,香蕉'; +const expectedChineseStrokeSort = '甘蔗,石榴,苹果,香蕉,梨,葡萄,橘子'; +const expectedMatchResult = 'Türkiye,TüRkiye'; +const expectedIndexList = ['…', 'A', 'B', 'C', 'Б', 'Г', 'Д', 'Ю', 'Я', '…']; +const expectedIndex = 'N'; + +@Extend(Text) +function textStyle() { + .fontSize(20) + .margin({ top: 20, left: 20, right: 20 }); +} + +@Entry +@Component +struct MultilingualSorting { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.MultilingualSorting') }) + Text($r('app.string.ResultsOfLocalSort')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(enArray.join(' '), expectedEnglishSort, $r('app.string.ResultOfEnglishSort'))) + .textStyle() + Text(assertEqual(zhArray.join(','), expectedChineseSort, $r('app.string.ResultOfChineseSort'))) + .textStyle() + Text(assertEqual(zhStrokeArray.join(','), expectedChineseStrokeSort, $r('app.string.ResultOfChineseStrokeSort'))) + .textStyle() + Text(assertEqual(matches.toString(), expectedMatchResult, $r('app.string.ResultOfSearchMatch'))) + .textStyle() + Text($r('app.string.ResultsOfCreateIndex')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqualLong(indexList.join(','), expectedIndexList, $r('app.string.ResultOfIndexList'))) + .textStyle(); + Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) { + Text(indexList.join(',')) + .textStyle() + }.direction(Direction.Ltr) + + Text(assertEqual(indexUtil.getIndex('你好'), expectedIndex, $r('app.string.ResultOfIndex'))) + .textStyle() + } + .alignItems(HorizontalAlign.Start) + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/NameLocalization.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/NameLocalization.ets new file mode 100644 index 0000000000000000000000000000000000000000..304317bfaf162e8e1cdf2815314332d635f27d68 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/NameLocalization.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual } from '../component/AssertEqual'; +import { i18n } from '@kit.LocalizationKit'; + +/********************************** + * 本地化语言与地区名称开发步骤 + **********************************/ + +let displayLanguage = i18n.System.getDisplayLanguage('de', 'zh-Hans-CN'); // 德文 +// language: 语言两字母代码,如"zh","de","fr"等 +// locale: 本地化标识符,如"en-GB"、"en-US"、"zh-Hans-CN"等 +// sentenceCase: 返回的语言名称是否需要首字母大写,默认值:true +let displayCountry = i18n.System.getDisplayCountry('SA', 'en-GB'); // Saudi Arabia +// country: 国家/地区两字母代码,如"CN"、"DE"、"SA"等 +// locale: 本地化标识符,如"en-GB"、"en-US"、"zh-Hans-CN"等 +// sentenceCase: 返回的国家/地区名称是否需要首字母大写,默认值:true + +/********************************** + * 本地化时区名称开发步骤 + **********************************/ + +let timezone = i18n.getTimeZone('America/Sao_Paulo'); +let timeZoneName = timezone.getDisplayName('zh-Hans', true); // 巴西利亚标准时间 + +const expectedDisplayLanguage = '德文'; +const expectedDisplayCountry = 'Saudi Arabia'; +const expectedTimeZoneName = '巴西利亚时间'; + +@Extend(Text) +function textStyle() { + .fontSize(20) + .margin({ top: 20, left: 20, right: 20 }); +} + +@Entry +@Component +struct NameLocalization { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.NameLocalization') }) + Text($r('app.string.ResultsOfLanguageRegion')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(displayLanguage, expectedDisplayLanguage, $r('app.string.DisplayLanguage'))) + .textStyle() + Text(assertEqual(displayCountry, expectedDisplayCountry, $r('app.string.DisplayCountry'))) + .textStyle() + Text($r('app.string.ResultsOfDisplayTimezone')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(timeZoneName, expectedTimeZoneName, $r('app.string.ResultOfTimezoneName'))) + .textStyle() + } + .alignItems(HorizontalAlign.Start) + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/NumberMeasurementFormatting.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/NumberMeasurementFormatting.ets new file mode 100644 index 0000000000000000000000000000000000000000..568856eaf40e4c7cd8bf6391db8a1f5d3e90cb17 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/NumberMeasurementFormatting.ets @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual } from '../component/AssertEqual'; +import { i18n, intl } from '@kit.LocalizationKit'; + +/********************************************************************************************************************** + * 数字格式化开发参考步骤 + * 1. 导入模块 + * import { intl } from '@kit.LocalizationKit'; + * 2. 创建NumberFormat对象 + * let numberFormat: intl.NumberFormat = + * new intl.NumberFormat(locale: string | Array, options?: NumberOptions); + * 3. 数字格式化,根据numberFormat的设置格式化number + * let formattedNumber: string = numberFormat.format(number: number); + * 4. 获取数字格式化选项,查看对象的设置信息 + * let options: intl.NumberOptions = numberFormat.resolvedOptions(); + *********************************************************************************************************************/ + +// 数字格式化开发示实例 +// 用科学计数法显示数字 +let numberFormat1 = new intl.NumberFormat('zh-CN', { notation: 'scientific', maximumSignificantDigits: 3 }); +let formattedNumber1 = numberFormat1.format(123400); // formattedNumber1: 1.23E5 + +// 用紧凑的格式显示数字 +let numberFormat2 = new intl.NumberFormat('zh-CN', { notation: 'compact', compactDisplay: 'short' }); +let formattedNumber2 = numberFormat2.format(123400); // formattedNumber2: 12万 + +// 显示数字的符号 +let numberFormat3 = new intl.NumberFormat('zh-CN', { signDisplay: 'always' }); +let formattedNumber3 = numberFormat3.format(123400); // formattedNumber3: +123,400 + +// 显示百分数 +let numberFormat4 = new intl.NumberFormat('zh-CN', { style: 'percent' }); +let formattedNumber4 = numberFormat4.format(0.25); // formattedNumber4: 25% + +// 货币和单位格式化开发实例 +// 格式化货币 +let numberFormat5 = new intl.NumberFormat('zh-CN', { style: 'currency', currency: 'USD' }); +let formattedNumber5 = numberFormat5.format(123400); // formattedNumber5: US$123,400.00 + +// 用名称表示货币 +let numberFormat6 = new intl.NumberFormat('zh-CN', { style: 'currency', currency: 'USD', currencyDisplay: 'name' }); +let formattedNumber6 = numberFormat6.format(123400); // formattedNumber6: 123,400.00美元 + +// 格式化度量衡 +let numberFormat7 = new intl.NumberFormat('en-GB', { style: 'unit', unit: 'hectare' }); +let formattedNumber7 = numberFormat7.format(123400); // formattedNumber7: 123,400 ha + +// 格式化特定场景下度量衡,如面积-土地-农业 +let numberFormat8 = new intl.NumberFormat('en-GB', { style: 'unit', unit: 'hectare', unitUsage: 'area-land-agricult' }); +let formattedNumber8 = numberFormat8.format(123400); // formattedNumber8: 304,928.041 ac + +/********************************************************************************************************************** + * 度量衡转换开发参考步骤 + * 1. 导入模块 + * import { i18n } from '@kit.LocalizationKit'; + * 2. 度量衡转换 + * let convertedUnit: string = + * i18n.I18NUtil.unitConvert(fromUnit: UnitInfo, toUnit: UnitInfo, value: number, locale: string, style?: string); + *********************************************************************************************************************/ + +// 度量衡转换开发实例 +// 设置要转换的单位和目标单位 +let fromUnit: i18n.UnitInfo = { unit: 'cup', measureSystem: 'US' }; +let toUnit: i18n.UnitInfo = { unit: 'liter', measureSystem: 'SI' }; + +// 以en-US区域参数转换度量衡 +let convertedUnit1 = i18n.I18NUtil.unitConvert(fromUnit, toUnit, 1000, 'en-US'); // convertedUnit1: 236.588 L + +// 显示完整的度量衡 +let convertedUnit2 = + i18n.I18NUtil.unitConvert(fromUnit, toUnit, 1000, 'en-US', 'long'); // convertedUnit2: 236.588 liters + +const expectedFormattedNumber1 = '1.23E5'; +const expectedFormattedNumber2 = '12万'; +const expectedFormattedNumber3 = '+123,400'; +const expectedFormattedNumber4 = '25%'; +const expectedFormattedNumber5 = 'US$123,400.00' +const expectedFormattedNumber6 = '123,400.00美元'; +const expectedFormattedNumber7 = '123,400 ha'; +const expectedFormattedNumber8 = '304,928.041 ac'; +const expectedConvertedUnit1 = '236.588 L'; +const expectedconvertedUnit2 = '236.588 liters'; + +@Extend(Text) +function textStyle() { + .fontSize(20) + .margin({ top: 15, left: 30, right: 30 }); +} + +@Entry +@Component +struct NumberMeasurementFormatting { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.NumberMeasurementFormatting') }) + Text($r('app.string.ResultsOfNumberFormat')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(formattedNumber1, expectedFormattedNumber1, $r('app.string.ScientificDisplayNumber'))) + .textStyle() + Text(assertEqual(formattedNumber2, expectedFormattedNumber2, $r('app.string.CompactDisplayNumber'))) + .textStyle() + Text(assertEqual(formattedNumber3, expectedFormattedNumber3, $r('app.string.SignDisplayNumber'))) + .textStyle() + Text(assertEqual(formattedNumber4, expectedFormattedNumber4, $r('app.string.PercentDisplayNumber'))) + .textStyle() + Text($r('app.string.ResultsOfCurrencyAndUnit')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(formattedNumber5, expectedFormattedNumber5, $r('app.string.DisplayCurrency'))) + .textStyle() + Text(assertEqual(formattedNumber6, expectedFormattedNumber6, $r('app.string.DisplayCurrencyName'))) + .textStyle() + Text(assertEqual(formattedNumber7, expectedFormattedNumber7, $r('app.string.DisplayUnit'))) + .textStyle() + Text(assertEqual(formattedNumber8, expectedFormattedNumber8, $r('app.string.DisplayUnitLand'))) + .textStyle() + Text($r('app.string.ResultsOfMeasureTrans')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(`${assertEqual(convertedUnit1, expectedConvertedUnit1, $r('app.string.MeasureTrans'))}`) + .textStyle() + Text(`${assertEqual(convertedUnit2, expectedconvertedUnit2, $r('app.string.LongMeasureTrans'))}`) + .textStyle() + } + .height('100%') + .width('100%') + .alignItems(HorizontalAlign.Start) + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/PhoneNumberFormatting.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/PhoneNumberFormatting.ets new file mode 100644 index 0000000000000000000000000000000000000000..3fc6c380ac240da011d11461f379f2d80c596e2f --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/PhoneNumberFormatting.ets @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual } from '../component/AssertEqual'; +import { i18n } from '@kit.LocalizationKit'; + +/********************************************************************************************************************** + * 电话号码格式化开发参考步骤 + * 1. 导入模块 + * import { i18n } from '@kit.LocalizationKit'; + * 2. 创建PhoneNumberFormat对象 + * let phoneNumberFormat: i18n.PhoneNumberFormat = + * new i18n.PhoneNumberFormat(country: string, options?: PhoneNumberFormatOptions); + * 3. 电话号码格式化 + * let formattedPhoneNumber: string = phoneNumberFormat.format(phoneNumber: string); + * 4. 判断电话号码正确性和号码归属地 + * let isValidNumber: boolean = phoneNumberFormat.isValidNumber(phoneNumber: string); // 判断电话号码正确性 + * let locationName: string = phoneNumberFormat.getLocationName(number: string, locale: string); // 获取号码归属地 + *********************************************************************************************************************/ + +// 电话号码格式化开发实例 +// 格式化电话号码 +let phoneNumberFormat1 = new i18n.PhoneNumberFormat('CN'); +let formattedPhoneNumber1 = phoneNumberFormat1.format('15812342312'); // formattedPhoneNumber1: 158 1234 2312 + +// RFC3966类型的电话号码 +let phoneNumberFormat2 = new i18n.PhoneNumberFormat('CN', { type: 'RFC3966' }); +let formattedPhoneNumber2 = phoneNumberFormat2.format('15812342312'); // formattedPhoneNumber2: tel:+86-158-1234-2312 + +// 判断电话号码是否有效 +let phoneNumberFormat3 = new i18n.PhoneNumberFormat('CN'); +let isValid = phoneNumberFormat3.isValidNumber('15812342312'); // isValid: true + +// 以某种语言显示号码归属地 +let phoneNumberFormat4 = new i18n.PhoneNumberFormat('CN'); +let locationName4 = phoneNumberFormat4.getLocationName('15812342312', 'en-GB'); // locationName4: Zhanjiang, Guangdong + +// 拨号中的电话号码格式化 +let phoneNumberFmt = new i18n.PhoneNumberFormat('CN', { type: 'TYPING' }); +let phoneNumber: string = '0755453'; +let formatResult: string = ''; +for (let i = 0; i < phoneNumber.length; i++) { + formatResult += phoneNumber.charAt(i); + formatResult = phoneNumberFmt.format(formatResult); +} +console.log(formatResult); // formatResult: 0755 453 + +const expectedFormattedPhoneNumber1 = '158 1234 2312'; +const expectedFormattedPhoneNumber2 = 'tel:+86-158-1234-2312'; +const expectedIsValid = true; +const expectedLocationName4 = 'Zhanjiang, Guangdong'; +const expectedFormatResult = '0755 453' + +@Extend(Text) +function textStyle() { + .fontSize(20) + .margin({ top: 30, left: 30, right: 30 }); +} + +@Entry +@Component +struct PhoneNumberFormatting { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.PhoneNumberFormatting') }) + Text($r('app.string.ResultsOfPhoneNumberFormat')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(formattedPhoneNumber1, expectedFormattedPhoneNumber1, $r('app.string.PhoneNumberFormat'))) + .textStyle() + Text(assertEqual(formattedPhoneNumber2, expectedFormattedPhoneNumber2, $r('app.string.RFC3966TypeNumberFormat'))) + .textStyle() + Text(assertEqual(isValid, expectedIsValid, $r('app.string.IsValidNumber'))) + .textStyle() + Text(assertEqual(locationName4, expectedLocationName4, $r('app.string.CNLocationName'))) + .textStyle() + Text(assertEqual(formatResult, expectedFormatResult, $r('app.string.FormatResult'))) + .textStyle() + } + .width('100%') + .height('100%') + .alignItems(HorizontalAlign.Start) + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/TimezoneDstSetting.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/TimezoneDstSetting.ets new file mode 100644 index 0000000000000000000000000000000000000000..a59a72622d86d50d9c82afbb93841355346342ec --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/i18napplication/TimezoneDstSetting.ets @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import { assertEqual, assertEqualLong } from '../component/AssertEqual'; +import { i18n } from '@kit.LocalizationKit'; + +/********************************************************************************************************************** + * 时区开发步骤 + *********************************************************************************************************************/ +// 时区相关功能开发实例 +// 获取巴西时区 +let timezone = i18n.getTimeZone('America/Sao_Paulo'); // 传入特定时区,创建时区类 +let timezoneId = timezone.getID(); // America/Sao_Paulo + +// 获取城市Id对应的时区对象 +let aucklandTimezone = i18n.TimeZone.getTimezoneFromCity('Auckland'); +let aucklandTzId = aucklandTimezone.getID(); // Pacific/Auckland + +// 时区的本地化名称 +let timeZoneName = timezone.getDisplayName('zh-Hans', true); // 巴西利亚标准时间 + +// 本地化城市名称 +let cityDisplayName = i18n.TimeZone.getCityDisplayName('Auckland', 'zh-Hans'); // 奥克兰 (新西兰) + +// 时区的固定偏移量 +let rawOffset = timezone.getRawOffset(); // -10800000 + +// 时区的实际偏移量(固定偏移量+夏令时) +let offset = timezone.getOffset(1234567890); // -10800000 + +// 系统支持的时区Id列表 +// ["America/Adak", "Asia/Hovd", "America/Sao_Paulo", "Asia/Jerusalem", "Europe/London",...] +let ids = i18n.TimeZone.getAvailableIDs(); + +// 系统支持的时区城市Id列表 +let cityIdArray = i18n.TimeZone.getAvailableZoneCityIDs(); // ["Auckland", "Magadan", "Lord Howe Island",...] + +// 遍历时区城市Id列表 +let timezoneList: Array = []; // 呈现给用户的时区列表 + +class Item { + cityDisplayName: string = ''; + timezoneId: string = ''; + offset: string = ''; + cityId: string = ''; +} + +for (let i = 0; i < cityIdArray.length; i++) { + let cityId = cityIdArray[i]; + let timezone = i18n.TimeZone.getTimezoneFromCity(cityId); // 城市Id对应的时区对象 + let cityDisplayName = i18n.TimeZone.getCityDisplayName(cityId, 'zh-CN'); // 本地化城市名称 + let timestamp = (new Date()).getTime(); + let item: Item = { + cityDisplayName: cityDisplayName, + timezoneId: timezone.getID(), + offset: 'GMT' + (timezone.getOffset(timestamp) / 3600 * 1000), + cityId: cityId + } + timezoneList.push(item); +} + +// 指定地理坐标所在的时区对象数组 +let timezoneArray = i18n.TimeZone.getTimezonesByLocation(-43.1, -22.5); +let locationTimezones: Array = []; +for (let i = 0; i < timezoneArray.length; i++) { + let tzId = timezoneArray[i].getID(); // America/Sao_Paulo + locationTimezones.push(tzId); +} + +// 双时钟应用开发实例 +// 选择时区列表中的时区放入应用偏好时区列表中 +let timezone1 = i18n.getTimeZone('America/Sao_Paulo'); +let timezone2 = i18n.getTimeZone(); +let appPreferredTimeZoneList: Array = []; // 应用偏好时区列表 +appPreferredTimeZoneList.push(timezone1); +appPreferredTimeZoneList.push(timezone2); + +// 选择时区列表中的时区放入应用偏好时区列表中 +let locale = i18n.System.getSystemLocale(); +let timeZoneData: Array = []; // 用于存储每个时区的时间信息 +// 遍历时区数组并获取时间信息 +for (let i = 0; i < appPreferredTimeZoneList.length; i++) { + let timezone = appPreferredTimeZoneList[i].getID(); + let calendar = i18n.getCalendar(locale); + calendar.setTimeZone(timezone); // 设置日历对象的时区 + // 获取年月日时分秒 + let year = calendar.get('year'); + let month = calendar.get('month'); + let day = calendar.get('date'); + let hour = calendar.get('hour'); + let minute = calendar.get('minute'); + let second = calendar.get('second'); + // 格式化时间信息并存储 + timeZoneData.push( + `时区: ${timezone}, 时间: ${year}-${month}-${day} ${hour}:${minute}:${second}` + ); +} + +/********************************************************************************************************************** + * 夏令时跳变实现原理 + *********************************************************************************************************************/ + +// 计算夏令时跳变前后同一个挂钟时间之间相差的小时数示例 +let calendar = i18n.getCalendar('zh-Hans'); +calendar.setTimeZone('Europe/London'); +calendar.set(2021, 2, 27, 16, 0, 0); // The day before daylight saving time start +let time1 = calendar.getTimeInMillis(); +calendar.set(2021, 2, 28, 16, 0, 0); // The day daylight saving time start +let time2 = calendar.getTimeInMillis(); +let hours = + (time2 - time1) / (3600 * 1000); // The hours between the same wall clock time before and after DST. Should be 23 + +const expectedTimezoneId = 'America/Sao_Paulo'; +const expectedAucklandTzId = 'Pacific/Auckland'; +const expectedTimeZoneName = '巴西利亚时间'; +const expectedCityDisplayName = '奥克兰 (新西兰)'; +const expectedRawOffset = -10800000; +const expectedOffset = -10800000; +const expectedIds = ['America/Adak', 'Asia/Hovd', 'America/Sao_Paulo', 'Asia/Jerusalem', 'Europe/London']; +const expectedCityIdArray = ['Auckland', 'Magadan', 'Lord Howe Island']; +const expectedTimeZoneCityList: Array = [ + { + cityDisplayName: '埃达克 (美国)', + timezoneId: 'America/Adak', + offset: 'GMT-9000000', + cityId: 'Adak' + }, + { + cityDisplayName: '安克雷奇 (美国)', + timezoneId: 'America/Anchorage', + offset: 'GMT-8000000', + cityId: 'Anchorage' + } +]; +const expectedTzId = 'America/Sao_Paulo'; +const expectedTimeZoneData = ['时区: America/Sao_Paulo', '时区: Asia/Shanghai']; +const expectedHours = 23; + +@Extend(Text) +function textStyle() { + .fontSize(18) + .margin({ top: 15, left: 30, right: 20 }); +} + +@Extend(Scroll) +function scrollStyle(scrollIndex: string) { + .height('20%') + .id(scrollIndex) + .width('80%') + .margin({ left: 50 }) + .border({ + width: 2, + color: $r('app.color.Border_Gray'), + style: BorderStyle.Solid, + radius: 10 + }) +} + +@Entry +@Component +struct TimezoneDstSetting { + build() { + Column() { + TitleBar({ hasBackPress: true, title: $r('app.string.TimezoneDstSetting') }) + Scroll() { + Column() { + Text($r('app.string.ResultsOfTimezoneFunction')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(timezoneId, expectedTimezoneId, $r('app.string.GetTimezoneID'))) + .textStyle() + Text(assertEqual(aucklandTzId, expectedAucklandTzId, $r('app.string.GetAucklandID'))) + .textStyle() + Text(assertEqual(timeZoneName, expectedTimeZoneName, $r('app.string.TimeZoneLocalName'))) + .textStyle() + Text(assertEqual(cityDisplayName, expectedCityDisplayName, $r('app.string.AucklandDisplayName'))) + .textStyle() + Text(assertEqual(rawOffset, expectedRawOffset, $r('app.string.GetRawOffset'))) + .textStyle() + Text(assertEqual(offset, expectedOffset, $r('app.string.GetOffset'))) + .textStyle() + Text(assertEqualLong(ids.join(', '), expectedIds, $r('app.string.GetAvailableIDs'))) + .textStyle() + Scroll() { + Text(ids.join(', ')) + .textStyle() + .id('idsText') + } + .scrollStyle('idsScroll') + + Text(assertEqualLong(cityIdArray.join(', '), expectedCityIdArray, $r('app.string.GetAvailableZoneCityIDs'))) + .textStyle() + Scroll() { + Text(cityIdArray.join(', ')) + .textStyle() + .id('cityIdArrayText') + } + .scrollStyle('cityIdArrayScroll') + + Text(assertEqualLong(JSON.stringify(timezoneList), + expectedTimeZoneCityList.map(item => JSON.stringify(item)), $r('app.string.TimezoneList'))) + .textStyle() + Scroll() { + Column() { + ForEach(timezoneList, (item: Item, index: number) => { + Column() { + Text(`${item.cityDisplayName},${item.timezoneId},${item.offset},${item.cityId}`) + .textStyle() + .id(`timezoneListText${index}`) + Divider().margin({ top: 3, left: 30, right: 30 }); + } + }, (item: Item, index: number) => `${item.cityId}-${index}` + ); + } + } + .scrollStyle('timezoneListScroll') + + Text(assertEqual(locationTimezones.join(','), expectedTzId, $r('app.string.IDOfGeographicCoordinate'))) + .textStyle() + Text(assertEqualLong(JSON.stringify(timeZoneData), expectedTimeZoneData, + $r('app.string.ResultsOfDualClockFeature'))) + .textStyle() + ForEach(timeZoneData, (item: string, index: number) => { + Text(item) + .textStyle() + }, (item: string, index: number) => `${index}` // 生成唯一标识符 + ); + + Text($r('app.string.ResultsOfDaylightSavingTimeJumps')) + .textStyle() + .fontWeight(FontWeight.Bold) + Text(assertEqual(hours, expectedHours, $r('app.string.DaylightSavingTimeHourDifference'))) + .textStyle() + Blank().height('5%') + } + .alignItems(HorizontalAlign.Start) + } + .id('outerScrollInTimezone') + .width('100%') + .height('100%') + } + } +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/ets/pages/Index.ets b/code/DocsSample/International/Internationalization/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..5b8d46080586e17c6b933e4581db139ad652ce14 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import TitleBar from '../component/TitleBar'; +import router from '@ohos.router'; + +interface Item { + text: string; +} + +const operationUrls: Array = [ + 'i18napplication/LocaleCulturalDivision', + 'i18napplication/LanguagePreferenceSetting', + 'i18napplication/DateTimeFormatting', + 'i18napplication/NumberMeasurementFormatting', + 'i18napplication/PhoneNumberFormatting', + 'i18napplication/CalendarSetting', + 'i18napplication/TimezoneDstSetting', + 'i18napplication/MultilingualSorting', + 'i18napplication/CharacterProcessing', + 'i18napplication/NameLocalization' +]; + +@Entry +@Component +struct Index { + ResourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + @State ListItem: Item[] = [ + { text: this.ResourceToString($r('app.string.LocaleCulturalDivisionExample')) }, + { text: this.ResourceToString($r('app.string.LanguagePreferenceSetting')) }, + { text: this.ResourceToString($r('app.string.DateTimeFormatting')) }, + { text: this.ResourceToString($r('app.string.NumberMeasurementFormatting')) }, + { text: this.ResourceToString($r('app.string.PhoneNumberFormatting')) }, + { text: this.ResourceToString($r('app.string.CalendarSetting')) }, + { text: this.ResourceToString($r('app.string.TimezoneDstSetting')) }, + { text: this.ResourceToString($r('app.string.MultilingualSorting')) }, + { text: this.ResourceToString($r('app.string.CharacterProcessing')) }, + { text: this.ResourceToString($r('app.string.NameLocalization')) } + ] + + build() { + Column() { + TitleBar() + List() { + ForEach(this.ListItem, (item: Item, index) => { + ListItem() { + Row() { + Blank().width('4%') + Text(item.text) + .fontSize(16) + .fontColor('black') + .width('90%') + Image($r('app.media.right')) + .height(12) + .width(12) + } + .onClick(() => { + router.pushUrl({ + url: operationUrls[index] + }) + }) + .border({ radius: 20 }) + .width('90%') + .height('8%') + .backgroundColor(Color.White) + .margin({ top: 12, left: 15, right: 8 }) + } + }) + } + .height('90%') + .width('100%') + } + .width('100%') + .height('100%') + .backgroundColor('#F1F3F5') + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/module.json5 b/code/DocsSample/International/Internationalization/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..2981c4d34daed1aa02d8281f340eb97a5df84318 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/module.json5 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 202 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ], + "requestPermissions":[ + { + "name" : "ohos.permission.UPDATE_CONFIGURATION", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "FormAbility" + ], + "when":"inuse" + } + }, + ] + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/color.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..81f76279f4de11bdbe6a85c50232cb5eb3c521b8 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/color.json @@ -0,0 +1,12 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + }, + { + "name": "Border_Gray", + "value": "#F1F3F5" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strCalendarSetting.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strCalendarSetting.json new file mode 100644 index 0000000000000000000000000000000000000000..c17b15c33e08029d249f8160dd85ad339affa071 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strCalendarSetting.json @@ -0,0 +1,64 @@ +{ + "string": [ + { + "name": "ResultsOfTheGregorianCalendar", + "value": "公历相关用法: " + }, + { + "name": "TheGregorianCalendarSets", + "value": "设置公历时间为2023/5/13 08:00:00" + }, + { + "name": "Timezone", + "value": "该时间时区: " + }, + { + "name": "FirstDayOfWeek", + "value": "该时间第一周的起始日: " + }, + { + "name": "MinimalDaysInFirstWeek", + "value": "该年第一周的最少天数: " + }, + { + "name": "SetMinimalDaysInFirstWeek", + "value": "设置一年中第一周的最少天数为3天: " + }, + { + "name": "YearOfTheFirstWeekIs3", + "value": "第一周最少天数是3的年份: " + }, + { + "name": "LocalizedCalendarName", + "value": "日历的本地化名称: " + }, + { + "name": "IsWeekend", + "value": "2023/10/15是否为周末: " + }, + { + "name": "DateAfterAddingDays", + "value": "2023/10/25加上2天后的日期: " + }, + { + "name": "DaysBetweenDates", + "value": "两个日期之间相差的天数: " + }, + { + "name": "LunarCalendar", + "value": "获取公历2023年6月25日对应的农历日期结果: " + }, + { + "name": "LunarYear", + "value": "2023/6/25对应的农历年: " + }, + { + "name": "LunarMonth", + "value": "2023/6/25对应的农历月: " + }, + { + "name": "LunarDate", + "value": "2023/6/25对应的农历日: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strCharacterProcessing.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strCharacterProcessing.json new file mode 100644 index 0000000000000000000000000000000000000000..ebd916e6a41c26a5924c5961fa78884606e4094e --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strCharacterProcessing.json @@ -0,0 +1,76 @@ +{ + "string": [ + { + "name": "ResultsOfCharacterType", + "value": "字符属性测试结果: " + }, + { + "name": "Character1IsNumber", + "value": "判断字符1是否是数字: " + }, + { + "name": "AIsRightToLeft", + "value": "判断字符a是否是从右到左语言的字符: " + }, + { + "name": "HuaIsIdeograph", + "value": "判断字符‘华’是否是表意文字: " + }, + { + "name": "AGetType", + "value": "字符a的一般类别值: " + }, + { + "name": "ResultsOfTrans", + "value": "音译测试结果: " + }, + { + "name": "CharacterTransResult", + "value": "中国,德国,美国,法国音译结果: " + }, + { + "name": "ChinaTrans", + "value": "汉语中国音译去声调: " + }, + { + "name": "TeachersSurnameTrans", + "value": "汉语单老师姓氏音译: " + }, + { + "name": "ZhangSunWuJiTrans", + "value": "汉语长孙无忌姓氏音译: " + }, + { + "name": "ResultsOfSupportedId", + "value": "音译支持的ID列表: " + }, + { + "name": "ResultsOfNormalize", + "value": "字符标准化测试结果: " + }, + { + "name": "NFCNormalizeResult", + "value": "以NFC范式标准化字符: " + }, + { + "name": "ResultsOfBreakIterator", + "value": "断句 Apple is my favorite fruit. 测试结果: " + }, + { + "name": "FirstPos", + "value": "首位置: " + }, + { + "name": "NextPos", + "value": "分割点位置: " + }, + { + "name": "IsBoundary", + "value": "是否是分割点: " + }, + { + "name": "BreakText", + "value": "断句文本: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strDateTimeFormat.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strDateTimeFormat.json new file mode 100644 index 0000000000000000000000000000000000000000..b752cd0358a8539ee078a13bc0b8c7da87d29209 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strDateTimeFormat.json @@ -0,0 +1,68 @@ +{ + "string": [ + { + "name": "ResultsOfDateTimeFormat", + "value": "时间日期格式化结果: " + }, + { + "name": "FullDateStyle", + "value": "在软件上展示完整的时间信息: " + }, + { + "name": "ShortDateStyle", + "value": "在有限的空间展示简短的时间信息: " + }, + { + "name": "CustomDateStyle", + "value": "自定义年月日时分秒的显示效果: " + }, + { + "name": "PartDateStyle", + "value": "仅显示一部分时间: " + }, + { + "name": "CustomTimeStyle", + "value": "自定义时制格式: " + }, + { + "name": "CustomNumberingSystem", + "value": "面向习惯于其他数字系统的用户: " + }, + { + "name": "FormatDateRange", + "value": "格式化时间段: " + }, + { + "name": "FormatDateStyle", + "value": "获取格式化选项: " + }, + { + "name": "ResultsOfRelativeTimeFormat", + "value": "相对时间格式化结果: " + }, + { + "name": "FormatRelativeTime", + "value": "显示相对时间: " + }, + { + "name": "AutoFormatRelativeTime", + "value": "口语化: " + }, + { + "name": "LongFormatRelativeTime", + "value": "部分语言支持更为简短的显示风格 (long): " + }, + { + "name": "NarrowFormatRelativeTime", + "value": "部分语言支持更为简短的显示风格 (narrow): " + }, + { + "name": "CustomFormatRelativeTime", + "value": "自定义区域设置格式的相对时间格式 (parts): " + }, + { + "name": "GetRelativeTimeFormatOptions", + "value": "获取RelativeTimeFormat对象的格式化选项 (numeric): " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strLanguagePreferenceSet.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strLanguagePreferenceSet.json new file mode 100644 index 0000000000000000000000000000000000000000..c0d19adeeada383b0723fa37d53c0a1695bf4012 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strLanguagePreferenceSet.json @@ -0,0 +1,40 @@ +{ + "string": [ + { + "name": "ResultsOfSetSystemLanguageAndRegion", + "value": "设置系统语言与区域结果: " + }, + { + "name": "SetAndGetSystemLanguage", + "value": "设置并获取系统语言为: " + }, + { + "name": "SetAndGetSystemRegion", + "value": "设置并获取系统地区为: " + }, + { + "name": "SetAndGetSystemLocale", + "value": "设置并获取系统区域为: " + }, + { + "name": "ResultsOfSetPreferredLanguage", + "value": "设置应用偏好语言结果: " + }, + { + "name": "SetAndGetPreferredLanguage", + "value": "设置并获取应用偏好语言为: " + }, + { + "name": "ResultsOfSetUserPreference", + "value": "设置用户偏好结果: " + }, + { + "name": "SetApplicationInterfaceNumber", + "value": "设置应用界面数字,2023年9月25日阿拉伯语为: " + }, + { + "name": "SetFormatTo24Format", + "value": "设置格式化的24小时制,格式化2023年9月25日16时48分0秒结果: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strLocaleCulturalDivision.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strLocaleCulturalDivision.json new file mode 100644 index 0000000000000000000000000000000000000000..b0a4441c1d09e23f785d1ef2ed385f351d990c62 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strLocaleCulturalDivision.json @@ -0,0 +1,28 @@ +{ + "string": [ + { + "name": "MethodOne", + "value": "方法一: " + }, + { + "name": "ResultOfMethodOne", + "value": "通过区域标识字符串创建区域标识对象结果: " + }, + { + "name": "MethodTwo", + "value": "方法二: " + }, + { + "name": "ResultOfMethodTwo", + "value": "通过区域标识字符串和LocaleOptions对象创建区域标识对象结果: " + }, + { + "name": "MethodThree", + "value": "方法三: " + }, + { + "name": "ResultOfMethodThree", + "value": "通过默认Locale函数创建系统区域标识对象结果: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strMultilingualSort.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strMultilingualSort.json new file mode 100644 index 0000000000000000000000000000000000000000..2caac783c4f6a428f42729603bd084cc788c36c3 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strMultilingualSort.json @@ -0,0 +1,36 @@ +{ + "string": [ + { + "name": "ResultsOfLocalSort", + "value": "本地习惯排序: " + }, + { + "name": "ResultOfEnglishSort", + "value": "英文区分大小写排序结果: \n" + }, + { + "name": "ResultOfChineseSort", + "value": "中文拼音排序结果: \n" + }, + { + "name": "ResultOfChineseStrokeSort", + "value": "中文按笔画排序结果: \n" + }, + { + "name": "ResultOfSearchMatch", + "value": "搜索匹配的字符串结果: " + }, + { + "name": "ResultsOfCreateIndex", + "value": "创建索引结果: " + }, + { + "name": "ResultOfIndexList", + "value": "混合语言索引列表: " + }, + { + "name": "ResultOfIndex", + "value": "\"你好\" 的索引: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strNameLocalization.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strNameLocalization.json new file mode 100644 index 0000000000000000000000000000000000000000..692cd1d410b857f4f06bdae10ce82cd163c635a1 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strNameLocalization.json @@ -0,0 +1,24 @@ +{ + "string": [ + { + "name": "ResultsOfLanguageRegion", + "value": "本地化语言与地区名称测试结果: " + }, + { + "name": "DisplayLanguage", + "value": "显示语言(以德文为例): " + }, + { + "name": "DisplayCountry", + "value": "显示国家/地区(沙特阿拉伯): " + }, + { + "name": "ResultsOfDisplayTimezone", + "value": "本地化时区名称测试结果: " + }, + { + "name": "ResultOfTimezoneName", + "value": "显示时区名称(以美洲/圣保罗为例): " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strNumberMeasure.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strNumberMeasure.json new file mode 100644 index 0000000000000000000000000000000000000000..651f05276419eadf0688e00c385ab2072f58273d --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strNumberMeasure.json @@ -0,0 +1,56 @@ +{ + "string": [ + { + "name": "ResultsOfNumberFormat", + "value": "数字格式化测试结果: " + }, + { + "name": "ScientificDisplayNumber", + "value": "科学计数法显示数字: " + }, + { + "name": "CompactDisplayNumber", + "value": "紧凑的格式显示数字: " + }, + { + "name": "SignDisplayNumber", + "value": "显示数字的符号: " + }, + { + "name": "PercentDisplayNumber", + "value": "显示百分数: " + }, + { + "name": "ResultsOfCurrencyAndUnit", + "value": "货币和单位格式化结果: " + }, + { + "name": "DisplayCurrency", + "value": "格式化货币: " + }, + { + "name": "DisplayCurrencyName", + "value": "名称表示货币: " + }, + { + "name": "DisplayUnit", + "value": "格式化度量衡: " + }, + { + "name": "DisplayUnitLand", + "value": "格式化特定场景下度量衡,如面积-土地-农业: " + }, + { + "name": "ResultsOfMeasureTrans", + "value": "度量衡转换结果: " + }, + { + "name": "MeasureTrans", + "value": "以en-US区域参数转换度量衡: " + }, + { + "name": "LongMeasureTrans", + "value": "显示完整的度量衡: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strPhoneNumberFormat.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strPhoneNumberFormat.json new file mode 100644 index 0000000000000000000000000000000000000000..4b6f9c1c638ff08ffa3d45489ce4ca520b159194 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strPhoneNumberFormat.json @@ -0,0 +1,28 @@ +{ + "string": [ + { + "name": "ResultsOfPhoneNumberFormat", + "value": "电话号码格式化结果: " + }, + { + "name": "PhoneNumberFormat", + "value": "格式化电话号码: " + }, + { + "name": "RFC3966TypeNumberFormat", + "value": "RFC3966类型的电话号码: " + }, + { + "name": "IsValidNumber", + "value": "判断电话号码是否有效: " + }, + { + "name": "CNLocationName", + "value": "以某种语言(以中文为例)显示号码归属地: " + }, + { + "name": "FormatResult", + "value": "拨号中的电话号码格式化: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strTimezoneDstSetting.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strTimezoneDstSetting.json new file mode 100644 index 0000000000000000000000000000000000000000..cffcabfd651e7844f9a1c887789e5a7a28579704 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/strTimezoneDstSetting.json @@ -0,0 +1,60 @@ +{ + "string": [ + { + "name": "ResultsOfTimezoneFunction", + "value": "时区功能结果: " + }, + { + "name": "GetTimezoneID", + "value": "获取巴西时区ID: " + }, + { + "name": "GetAucklandID", + "value": "获取奥克兰时区ID: " + }, + { + "name": "TimeZoneLocalName", + "value": "时区的本地化名称: " + }, + { + "name": "AucklandDisplayName", + "value": "奥克兰本地化城市名称: " + }, + { + "name": "GetRawOffset", + "value": "巴西时区的固定偏移量: " + }, + { + "name": "GetOffset", + "value": "巴西时区的实际偏移量: " + }, + { + "name": "GetAvailableIDs", + "value": "系统支持的时区ID列表: " + }, + { + "name": "GetAvailableZoneCityIDs", + "value": "系统支持的时区城市ID列表: " + }, + { + "name": "TimezoneList", + "value": "时区城市列表: " + }, + { + "name": "IDOfGeographicCoordinate", + "value": "指定地理坐标所在的时区ID: " + }, + { + "name": "ResultsOfDualClockFeature", + "value": "双时钟应用功能结果: " + }, + { + "name": "ResultsOfDaylightSavingTimeJumps", + "value": "夏令时跳变测试结果: " + }, + { + "name": "DaylightSavingTimeHourDifference", + "value": "2021年2月27日16:00(夏令时前一天)到2021年2月28日16:00(夏令时当天)的小时差: " + } + ] +} diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/string.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..10d73e4848f833d14d70fa3ca228329436551462 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/element/string.json @@ -0,0 +1,68 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "国际化" + }, + { + "name": "Internationalization", + "value": "国际化" + }, + { + "name": "LocaleCulturalDivision", + "value": "区域标识与文化习惯划分" + }, + { + "name": "LocaleCulturalDivisionExample", + "value": "区域标识与文化习惯划分 (时间日期格式化为例)" + }, + { + "name": "LanguagePreferenceSetting", + "value": "设置语言与用户偏好" + }, + { + "name": "DateTimeFormatting", + "value": "时间日期国际化" + }, + { + "name": "NumberMeasurementFormatting", + "value": "数字与度量衡国际化" + }, + { + "name": "PhoneNumberFormatting", + "value": "电话号码格式化" + }, + { + "name": "CalendarSetting", + "value": "设置日历和历法" + }, + { + "name": "TimezoneDstSetting", + "value": "时区与夏令时国际化" + }, + { + "name": "MultilingualSorting", + "value": "多语言排序" + }, + { + "name": "CharacterProcessing", + "value": "字符处理" + }, + { + "name": "NameLocalization", + "value": "本地化名称" + }, + { + "name": "reason", + "value": "用于更新系统配置" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/back.svg b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/back.svg new file mode 100644 index 0000000000000000000000000000000000000000..0614389ee6f66cd188d47ba045aa83b4babee356 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/back.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/background.png b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/background.png differ diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/foreground.png b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/foreground.png differ diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/layered_image.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/right.svg b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/right.svg new file mode 100644 index 0000000000000000000000000000000000000000..f743acf7d50d9b4818e54d14596d2f71243ba7f2 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/startIcon.png b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/media/startIcon.png differ diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/profile/backup_config.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/base/profile/main_pages.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..b4d000b6da64c7f7580d3b5fd346bdbfcf3bf8ab --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,15 @@ +{ + "src": [ + "pages/Index", + "i18napplication/LocaleCulturalDivision", + "i18napplication/LanguagePreferenceSetting", + "i18napplication/DateTimeFormatting", + "i18napplication/NumberMeasurementFormatting", + "i18napplication/PhoneNumberFormatting", + "i18napplication/CalendarSetting", + "i18napplication/TimezoneDstSetting", + "i18napplication/MultilingualSorting", + "i18napplication/CharacterProcessing", + "i18napplication/NameLocalization" + ] +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/en_US/element/string.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..16dc430425de75f443b5e702ee6732f7765b574a --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Internationalization" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/main/resources/zh_CN/element/string.json b/code/DocsSample/International/Internationalization/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..4031df99cdc40128c73d9bd8d2085ba86411a1e8 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "国际化" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/mock/mock-config.json5 b/code/DocsSample/International/Internationalization/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b9a78e201535765168a92d3543c690273ecdc019 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/ohosTest/ets/test/I18n.test.ets b/code/DocsSample/International/Internationalization/entry/src/ohosTest/ets/test/I18n.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..04b7575a42b26fe25c1db6170de6288b4bbcbdf0 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/ohosTest/ets/test/I18n.test.ets @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from '@ohos/hypium'; +import { abilityDelegatorRegistry, Driver, MatchPattern, ON } from '@kit.TestKit'; +import hilog from '@ohos.hilog'; + +const BUNDLE = 'I18nTest_'; +const TAG: string = '[Sample_Internationalization]'; +const DOMAIN = 0xF811; +const DELAY_TIME = 500; +const SCROLL_SPEED = 3000; +const delegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let driver: Driver = Driver.create(); + +async function checkAndClickByText(text: string) { + await driver.assertComponentExist(ON.text(text, MatchPattern.CONTAINS)); + let component = await driver.findComponent(ON.text(text)); + await component.click(); + await driver.delayMs(DELAY_TIME); +} + +async function goBack() { + await driver.assertComponentExist(ON.id('btnBack')); + let backButton = await driver.findComponent(ON.id('btnBack')); + await backButton.click(); + await driver.delayMs(DELAY_TIME); +} + +async function scrollView(scrollId: string, textId: string, arr: string[]) { + let scroll = await driver.findComponent(ON.id(scrollId)); + await driver.delayMs(DELAY_TIME); + await scroll.scrollToBottom(SCROLL_SPEED); + let text = await driver.findComponents(ON.id(textId)); + expect(text).not().assertNull(); + if (!Array.isArray(text)) { + throw new Error('Expected an array of components, but received a different type'); + } + expect(text.length).not().assertNull(); + for (let index = 0; index < Math.min(text.length, arr.length); index++) { + const element = text[index]; + const actualText = await element.getText(); + expect(actualText.includes(arr[index].toString())).assertTrue(); + } + await driver.delayMs(DELAY_TIME); +} + +async function scrollOuterBottomView(scrollId: string) { + let scroll = await driver.findComponent(ON.id(scrollId)); + await driver.delayMs(DELAY_TIME); + await scroll.scrollToBottom(SCROLL_SPEED); + await driver.delayMs(DELAY_TIME); +} + +const expectedIdsText = ['America/Adak', 'Asia/Hovd', 'America/Sao_Paulo', 'Asia/Jerusalem', 'Europe/London']; +const expectedCityIdArrayText = ['Auckland', 'Magadan', 'Lord Howe Island']; +const expectedTimezoneListText = ['埃里温 (亚美尼亚)', 'Asia/Yerevan', 'GMT4000000', 'Yerevan']; +const expectedTransIdsText = ['ASCII-Latin', 'Accents-Any']; +const LAST_INDEX = 23; + +function ResourceToString(resource: Resource): string { + return getContext().resourceManager.getStringSync(resource); +} + +export default function abilityTest() { + describe('I18nTestSuite', () => { + /** + * @tc.number LaunchIndexPage_001 + * @tc.name LaunchIndexPage_001 + * @tc.desc 启动应用 + */ + it(BUNDLE + 'LaunchIndexPage_001', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'LaunchIndexPage_001, begin'); + await delegator.startAbility({ + bundleName: bundleName, + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.LocaleCulturalDivisionExample')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.LanguagePreferenceSetting')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.DateTimeFormatting')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.NumberMeasurementFormatting')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.PhoneNumberFormatting')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.CalendarSetting')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.TimezoneDstSetting')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.MultilingualSorting')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.CharacterProcessing')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.NameLocalization')))); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'LaunchIndexPage_001, end'); + }); + + /** + * @tc.number I18nTestLocaleCulturalDivision_002 + * @tc.name I18nTestLocaleCulturalDivision_002 + * @tc.desc 区域标识与文化习惯划分(时间日期格式化为例) + */ + it(BUNDLE + 'LocaleCulturalDivision_002', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'LocaleCulturalDivision_002, begin'); + await checkAndClickByText(ResourceToString($r('app.string.LocaleCulturalDivisionExample'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.MethodOne')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ResultOfMethodOne'))}2023/10/15 --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.MethodTwo')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ResultOfMethodTwo'))}10/15/23 --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.MethodThree')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ResultOfMethodThree'))}2023/10/15 --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'LocaleCulturalDivision_002, end'); + }); + + /** + * @tc.number I18nTestLanguagePreferenceSetting_003 + * @tc.name I18nTestLanguagePreferenceSetting_003 + * @tc.desc 设置语言与用户偏好 + */ + it(BUNDLE + 'LanguagePreferenceSetting_003', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'LanguagePreferenceSetting_003, begin'); + await checkAndClickByText(ResourceToString($r('app.string.LanguagePreferenceSetting'))); + await driver.assertComponentExist( + ON.text(ResourceToString($r('app.string.ResultsOfSetSystemLanguageAndRegion')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.SetAndGetSystemLanguage'))}zh --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.SetAndGetSystemRegion'))}CN --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.SetAndGetSystemLocale'))}zh-Hans-CN --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfSetPreferredLanguage')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.SetAndGetPreferredLanguage'))}zh-Hans --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfSetUserPreference')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.SetApplicationInterfaceNumber'))}٢٥‏/١٠‏/٢٠٢٣ --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.SetFormatTo24Format'))}16:48:00 --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'LanguagePreferenceSetting_003, end'); + }); + + /** + * @tc.number I18nTestDateTimeFormatting_004 + * @tc.name I18nTestDateTimeFormatting_004 + * @tc.desc 时间日期国际化 + */ + it(BUNDLE + 'DateTimeFormatting_004', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'DateTimeFormatting_004, begin'); + await checkAndClickByText(ResourceToString($r('app.string.DateTimeFormatting'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfDateTimeFormat')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.FullDateStyle'))}2021年9月17日星期五 中国标准时间 13:04:00 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ShortDateStyle'))}2021/9/17 13:04 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.CustomDateStyle'))}2021/09/17 13:04:00 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.PartDateStyle'))}9月17日星期五 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.CustomTimeStyle'))}2021/9/17 下午13:04 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.CustomNumberingSystem'))}٢٠٢١/٩/١٧ ١٣:٠٤ --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.FormatDateRange'))}17/09/2021 – 18/09/2021 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.FormatDateStyle'))}full --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfRelativeTimeFormat')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.FormatRelativeTime'))}1 day ago --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.AutoFormatRelativeTime'))}yesterday --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.LongFormatRelativeTime'))}il y a 1 jour --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.NarrowFormatRelativeTime'))}-1 j --passed`)); + await driver.assertComponentExist( + ON.text(ResourceToString($r('app.string.CustomFormatRelativeTime')) + + '[{"type":"literal","value":"in "},' + + '{"type":"integer","value":"1","unit":"day"},' + + '{"type":"literal","value":" day"}] --passed' + ) + ); + await scrollOuterBottomView('outerScrollInDateTime'); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.GetRelativeTimeFormatOptions'))}auto --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'DateTimeFormatting_004, end'); + }); + + /** + * @tc.number I18nTestNumberMeasurementFormatting_005 + * @tc.name I18nTestNumberMeasurementFormatting_005 + * @tc.desc 数字与度量衡国际化 + */ + it(BUNDLE + 'NumberMeasurementFormatting_005', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'NumberMeasurementFormatting_005, begin'); + await checkAndClickByText(ResourceToString($r('app.string.NumberMeasurementFormatting'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfNumberFormat')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ScientificDisplayNumber'))}1.23E5 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.CompactDisplayNumber'))}12万 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.SignDisplayNumber'))}+123,400 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.PercentDisplayNumber'))}25% --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfCurrencyAndUnit')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.DisplayCurrency'))}US$123,400.00 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.DisplayCurrencyName'))}123,400.00美元 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.DisplayUnit'))}123,400 ha --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.DisplayUnitLand'))}304,928.041 ac --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfMeasureTrans')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.MeasureTrans'))}236.588 L --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.LongMeasureTrans'))}236.588 liters --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'NumberMeasurementFormatting_005, end'); + }); + + /** + * @tc.number I18nTestPhoneNumberFormatting_006 + * @tc.name I18nTestPhoneNumberFormatting_006 + * @tc.desc 电话号码格式化 + */ + it(BUNDLE + 'PhoneNumberFormatting_006', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'PhoneNumberFormatting, begin'); + await checkAndClickByText(ResourceToString($r('app.string.PhoneNumberFormatting'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfPhoneNumberFormat')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.PhoneNumberFormat'))}158 1234 2312 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.RFC3966TypeNumberFormat'))}tel:+86-158-1234-2312 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.IsValidNumber'))}true --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.CNLocationName'))}Zhanjiang, Guangdong --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.FormatResult'))}0755 453 --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'PhoneNumberFormatting_006, end'); + }); + + /** + * @tc.number I18nTestCalendarFormatting_007 + * @tc.name I18nTestCalendarFormatting_007 + * @tc.desc 设置日历和历法 + */ + it(BUNDLE + 'CalendarFormatting_007', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'CalendarFormatting_007, begin'); + await checkAndClickByText(ResourceToString($r('app.string.CalendarSetting'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfTheGregorianCalendar')))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.TheGregorianCalendarSets')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.Timezone'))}Asia/Shanghai --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.FirstDayOfWeek'))}1 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.MinimalDaysInFirstWeek'))}1 --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.SetMinimalDaysInFirstWeek')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.YearOfTheFirstWeekIs3'))}2022 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.LocalizedCalendarName'))}公历 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.IsWeekend'))}true --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.DateAfterAddingDays'))}17 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.DaysBetweenDates'))}-3 --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.LunarCalendar')))); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.LunarYear'))}40 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.LunarMonth'))}5 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.LunarDate'))}8 --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'CalendarFormatting_007, end'); + }); + + /** + * @tc.number I18nTestTimezoneDstSetting_008 + * @tc.name I18nTestTimezoneDstSetting_008 + * @tc.desc 时区与夏令时国际化 + */ + it(BUNDLE + 'TimezoneDstSetting_008', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'TimezoneDstSetting_008, begin'); + await checkAndClickByText(ResourceToString($r('app.string.TimezoneDstSetting'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfTimezoneFunction')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.GetTimezoneID'))}America/Sao_Paulo --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.GetAucklandID'))}Pacific/Auckland --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.TimeZoneLocalName'))}巴西利亚`, + MatchPattern.CONTAINS)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.AucklandDisplayName'))}奥克兰 (新西兰) --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.GetRawOffset'))}-10800000 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.GetOffset'))}-10800000 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.GetAvailableIDs'))}passed`)); + await scrollView('idsScroll', 'idsText', expectedIdsText) + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.GetAvailableZoneCityIDs'))}passed`)); + await scrollView('cityIdArrayScroll', 'cityIdArrayText', expectedCityIdArrayText); + await scrollOuterBottomView('outerScrollInTimezone'); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.TimezoneList'))}passed`)); + await scrollView('timezoneListScroll', `timezoneListText${LAST_INDEX}`, expectedTimezoneListText); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.IDOfGeographicCoordinate'))}America/Sao_Paulo --passed`)) + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ResultsOfDualClockFeature'))}passed`)); + await driver.assertComponentExist(ON.text('时区: America/Sao_Paulo, 时间: ', MatchPattern.CONTAINS)) + await driver.assertComponentExist(ON.text('时区: Asia/Shanghai, 时间: ', MatchPattern.CONTAINS)) + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfDaylightSavingTimeJumps')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.DaylightSavingTimeHourDifference'))}23 --passed`, + MatchPattern.CONTAINS)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'TimezoneDstSetting_008, end'); + }); + + /** + * @tc.number I18nTestMultilingualSorting_009 + * @tc.name I18nTestMultilingualSorting_009 + * @tc.desc 多语言排序 + */ + it(BUNDLE + 'MultilingualSorting_009', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'MultilingualSorting_009, begin'); + await checkAndClickByText(ResourceToString($r('app.string.MultilingualSorting'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfLocalSort')))); + await driver.assertComponentExist(ON.text( + `${ResourceToString($r('app.string.ResultOfEnglishSort'))}animal ANIMAL app App apple Apple APPLE --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ResultOfChineseSort'))}甘蔗,橘子,梨,苹果,葡萄,石榴,香蕉 --passed`)); + await driver.assertComponentExist(ON.text( + `${ResourceToString($r('app.string.ResultOfChineseStrokeSort'))}甘蔗,石榴,苹果,香蕉,梨,葡萄,橘子 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ResultOfSearchMatch'))}Türkiye,TüRkiye --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfCreateIndex')))); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.ResultOfIndexList'))}passed`)); + await driver.assertComponentExist(ON.text('…,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,' + + '…,А,Б,В,Г,Д,Е,Ж,З,И,Й,К,Л,М,Н,О,П,Р,С,Т,У,Ф,Х,Ц,Ч,Ш,Щ,Ы,Э,Ю,Я,…')); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.ResultOfIndex'))}N --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'MultilingualSorting_009, end'); + }); + + /** + * @tc.number I18nTestCharacterProcessing_010 + * @tc.name I18nTestCharacterProcessing_010 + * @tc.desc 字符处理 + */ + it(BUNDLE + 'CharacterProcessing_010', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'CharacterProcessing_010, begin'); + await checkAndClickByText(ResourceToString($r('app.string.CharacterProcessing'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfCharacterType')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.Character1IsNumber'))}true --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.AIsRightToLeft'))}false --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.HuaIsIdeograph'))}true --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.AGetType'))}U_LOWERCASE_LETTER --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfTrans')))); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.CharacterTransResult'))}zhōng guó,dé guó,měi guó,fǎ guó --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.ChinaTrans'))}zhong guo --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.TeachersSurnameTrans'))}shàn lǎo shī --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.ZhangSunWuJiTrans'))}zhǎng sūn wú jì --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.ResultsOfSupportedId'))}passed`)); + await scrollView('transIdsScroll', 'transIdsText', expectedTransIdsText); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfNormalize')))); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.NFCNormalizeResult'))}ẛ̣ --passed`)); + await scrollOuterBottomView('outerScrollInCharacter'); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfBreakIterator')))); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.FirstPos'))}0 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.NextPos'))}9 --passed`)); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.IsBoundary'))}true --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.BreakText'))}Apple is my favorite fruit. --passed`)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'CharacterProcessing_010, end'); + }); + + /** + * @tc.number I18nTestNameLocalization_011 + * @tc.name I18nTestNameLocalization_011 + * @tc.desc 本地化名称 + */ + it(BUNDLE + 'NameLocalization_011', 0, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'NameLocalization_011, begin'); + await checkAndClickByText(ResourceToString($r('app.string.NameLocalization'))); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfLanguageRegion')))); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.DisplayLanguage'))}德文 --passed`)); + await driver.assertComponentExist( + ON.text(`${ResourceToString($r('app.string.DisplayCountry'))}Saudi Arabia --passed`)); + await driver.assertComponentExist(ON.text(ResourceToString($r('app.string.ResultsOfDisplayTimezone')))); + await driver.assertComponentExist(ON.text(`${ResourceToString($r('app.string.ResultOfTimezoneName'))}巴西利亚`, + MatchPattern.CONTAINS)); + await goBack(); + done(); + hilog.info(DOMAIN, TAG, BUNDLE + 'NameLocalization_011, end'); + }); + }); +} diff --git a/code/DocsSample/International/Internationalization/entry/src/ohosTest/ets/test/List.test.ets b/code/DocsSample/International/Internationalization/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..d3eaa18d1646f14944ca7e811c1c711bb5fb1e13 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import abilityTest from './I18n.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/ohosTest/module.json5 b/code/DocsSample/International/Internationalization/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c3fd9dda3040d888d9d8b0b62bcb5d3b6fbeb614 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/code/DocsSample/International/Internationalization/entry/src/test/List.test.ets b/code/DocsSample/International/Internationalization/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/entry/src/test/LocalUnit.test.ets b/code/DocsSample/International/Internationalization/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/code/DocsSample/International/Internationalization/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/code/DocsSample/International/Internationalization/hvigor/hvigor-config.json5 b/code/DocsSample/International/Internationalization/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..43beb743cbd25c3507b1cf8a744bf8197b3bf2fb --- /dev/null +++ b/code/DocsSample/International/Internationalization/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/code/DocsSample/International/Internationalization/hvigorfile.ts b/code/DocsSample/International/Internationalization/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a5e543f190732c159beb574dfc9fa37bc94e156 --- /dev/null +++ b/code/DocsSample/International/Internationalization/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/code/DocsSample/International/Internationalization/oh-package.json5 b/code/DocsSample/International/Internationalization/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..952ab183532e81c9c50e5de1e64393704e1e48fe --- /dev/null +++ b/code/DocsSample/International/Internationalization/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.18", + "@ohos/hamock": "1.0.0" + } +} diff --git a/code/DocsSample/International/Internationalization/ohosTest.md b/code/DocsSample/International/Internationalization/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..3845a3e7e8d0d0bed0624a3747540eb2be56e5cc --- /dev/null +++ b/code/DocsSample/International/Internationalization/ohosTest.md @@ -0,0 +1,17 @@ +# Internationalization国际化测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| :------: | :------: | :------: | :------: | :------: | :------: | +| 拉起应用1 | 设备正常运行 | \ | 成功拉起应用,在主页停留3秒,判断主页Text显示正确。 | 是 | Pass | +| 测试实例2 | 位于区域标识与文化习惯划分页面 | \ | 点击区域标识与文化习惯划分模块按钮,切换到实例2页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例3 | 位于设置语言与用户偏好页面 | \ | 点击设置语言与用户偏好模块按钮,切换到实例3页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例4 | 位于时间日期国际化页面 | \ | 点击时间日期国际化模块按钮,切换到实例4页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例5 | 位于数字与度量衡国际化页面 | \ | 点击数字与度量衡国际化模块按钮,切换到实例5页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例6 | 位于电话号码格式化页面 | \ | 点击电话号码格式化模块按钮,切换到实例6页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例7 | 位于设置日历和历法页面 | \ | 点击设置日历和历法模块按钮,切换到实例7页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | pass | +| 测试实例8 | 位于时区与夏令时国际化页面 | \ | 点击时区与夏令时国际化模块按钮,切换到实例8页面,并判断输出Text结果正确,测试滑动窗口可以滚动并测试窗口内Text内容输出正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例9 | 位于多语言排序页面 | \ | 点击多语言排序模块按钮,切换到实例9页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例10 | 位于字符处理页面 | \ | 点击字符处理模块按钮,切换到实例10页面,并判断输出Text结果正确,测试滑动窗口可以滚动并测试窗口内Text内容输出正确,并退出当前页面返回主页面。 | 是 | Pass | +| 测试实例11 | 位于字符处理页面 | \ | 点击字符处理模块按钮,切换到实例11页面,并判断输出Text结果正确,并退出当前页面返回主页面。 | 是 | Pass | diff --git a/code/DocsSample/International/Internationalization/screenshots/CalendarSetting.jpg b/code/DocsSample/International/Internationalization/screenshots/CalendarSetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..debcca010650acfe30c811d6c5246b7dbef9bd14 Binary files /dev/null and b/code/DocsSample/International/Internationalization/screenshots/CalendarSetting.jpg differ diff --git a/code/DocsSample/International/Internationalization/screenshots/DateTimeFormatting.jpg b/code/DocsSample/International/Internationalization/screenshots/DateTimeFormatting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fd135100fffb20be989ce56bfeb850d2f73606d7 Binary files /dev/null and b/code/DocsSample/International/Internationalization/screenshots/DateTimeFormatting.jpg differ diff --git a/code/DocsSample/International/Internationalization/screenshots/LocaleCulturalDivision.jpg b/code/DocsSample/International/Internationalization/screenshots/LocaleCulturalDivision.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de6ba2a27547bf93e7d011fcf5e865ca2a20ade6 Binary files /dev/null and b/code/DocsSample/International/Internationalization/screenshots/LocaleCulturalDivision.jpg differ diff --git a/code/DocsSample/International/Internationalization/screenshots/MainPage.jpg b/code/DocsSample/International/Internationalization/screenshots/MainPage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..abf5e62d426a3a80828d42f49b2eb0fbe1df650b Binary files /dev/null and b/code/DocsSample/International/Internationalization/screenshots/MainPage.jpg differ